Lekce 7 - JNI - Primitivní datové typy
V minulém tutoriálu o Java Native Interface, JNI - Příklad v Eclipse s C++, jsme si vyzkoušeli pokročilejší příklad s řetězci a C++.
V dnešním dílu se budeme věnovat primitivním datovým typům.
Primitivní datové typy
V předchozích dílech jsme si ukázali funkční postupy vytvářející *.dll. Nyní si vyberte, který vám vyhovuje, a vyzkoušejte si různé primitivní datové typy, které tu budou zveřejněny. Není to nijak složité, když existuje vzorový příklad. Zde je seznam všech primitivních datových typů dostupných jak v Javě, Cčku, tak i v nativní části (JNI).
JAVA typy | JNI typy | C typy | JNI Velikost(bit) |
---|---|---|---|
boolean | jboolean | neobsahuje | 8 (unsigned) |
byte | jbyte | neobsahuje | 8 |
char | jchar | char | 16 (unsigned) |
short | jshort | short | 16 |
int | jint | int | 32 |
long | jlong | long | 64 |
float | jfloat | float | 32 |
double | jdouble | double | 64 |
void | void | void | 0 |
true | JNI_TRUE | 1 | - |
false | JNI_FALSE | 0 | - |
Popis metod je docela jednoduchý.
public class DatoveTypyPrimitivni { static { //... načteme dll } private native void vypisBoolean(boolean hodnota); private native boolean ziskejBoolean(); private native void vypisByte(byte hodnota); private native byte ziskejByte(); private native void vypisZnak(char znak); private native char ziskejZnak(); private native void nastavShort(short hodnota); private native short ziskejShort(); private native void nastavInt(int hodnota); private native int ziskejInt(); private native void nastavLont(long hodnota); private native long ziskejLong(); private native void nastavFloat(float hodnota); private native float ziskejFloat(); private native void nastavDouble(double hodnota); private native double ziskejDouble(); // Konzolovy vypis JNI metod probehne az na konci celeho naseho programu public static void main(String args []){ System.out.println("Start Programu"); DatoveTypyPrimitivni program = new DatoveTypyPrimitivni(); program.vypisBoolean(false); System.out.println("Zde je hodnota z JNI : "+program.ziskejBoolean()); program.vypisByte((byte)77); System.out.println("Ziskej hodnotu z Byte z JNI : "+program.ziskejByte()); program.vypisZnak('Z'); System.out.println("Ziskej Znak z JNI : "+program.ziskejZnak()); short hodnota = 14563; program.nastavShort(hodnota); System.out.println("Ziskej short z JNI : "+program.ziskejShort()); program.nastavInt(12312345); System.out.println("Ziskej int z JNI : "+program.ziskejInt()); long hodnotaLong = (long)674843456; program.nastavLont(hodnotaLong); System.out.println("Ziskej long z JNI : "+program.ziskejLong()); float hodnotaFloat = (float) 4565.35967; program.nastavFloat(hodnotaFloat); System.out.println("Ziskej float z JNI : "+program.ziskejFloat()); double hodnotaDouble = (double)45456465.45994; program.nastavDouble(hodnotaDouble); System.out.println("Ziskej double z JNI : "+program.ziskejDouble()); System.out.println("Konec Programu"); } }
Zde je vygenerovaný header file. Pojmenovaný "primitivni.h".
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class DatoveTypyPrimitivni */ #ifndef _Included_DatoveTypyPrimitivni #define _Included_DatoveTypyPrimitivni #ifdef __cplusplus extern "C" { #endif /* * Class: DatoveTypyPrimitivni * Method: vypisBoolean * Signature: (Z)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisBoolean (JNIEnv *, jobject, jboolean); /* * Class: DatoveTypyPrimitivni * Method: ziskejBoolean * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_DatoveTypyPrimitivni_ziskejBoolean (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: vypisByte * Signature: (B)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisByte (JNIEnv *, jobject, jbyte); /* * Class: DatoveTypyPrimitivni * Method: ziskejByte * Signature: ()B */ JNIEXPORT jbyte JNICALL Java_DatoveTypyPrimitivni_ziskejByte (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: vypisZnak * Signature: (C)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisZnak (JNIEnv *, jobject, jchar); /* * Class: DatoveTypyPrimitivni * Method: ziskejZnak * Signature: ()C */ JNIEXPORT jchar JNICALL Java_DatoveTypyPrimitivni_ziskejZnak (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: nastavShort * Signature: (S)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavShort (JNIEnv *, jobject, jshort); /* * Class: DatoveTypyPrimitivni * Method: ziskejShort * Signature: ()S */ JNIEXPORT jshort JNICALL Java_DatoveTypyPrimitivni_ziskejShort (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: nastavInt * Signature: (I)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavInt (JNIEnv *, jobject, jint); /* * Class: DatoveTypyPrimitivni * Method: ziskejInt * Signature: ()I */ JNIEXPORT jint JNICALL Java_DatoveTypyPrimitivni_ziskejInt (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: nastavLont * Signature: (J)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavLont (JNIEnv *, jobject, jlong); /* * Class: DatoveTypyPrimitivni * Method: ziskejLong * Signature: ()J */ JNIEXPORT jlong JNICALL Java_DatoveTypyPrimitivni_ziskejLong (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: nastavFloat * Signature: (F)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavFloat (JNIEnv *, jobject, jfloat); /* * Class: DatoveTypyPrimitivni * Method: ziskejFloat * Signature: ()F */ JNIEXPORT jfloat JNICALL Java_DatoveTypyPrimitivni_ziskejFloat (JNIEnv *, jobject); /* * Class: DatoveTypyPrimitivni * Method: nastavDouble * Signature: (D)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavDouble (JNIEnv *, jobject, jdouble); /* * Class: DatoveTypyPrimitivni * Method: ziskejDouble * Signature: ()D */ JNIEXPORT jdouble JNICALL Java_DatoveTypyPrimitivni_ziskejDouble (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
Nyní si konečně probereme co znamená popis v header file u jednotlivých metod. Např.:
/*
* Class: DatoveTypyPrimitivni
* Method: vypisBoolean
* Signature: (Z)V
*/
- Class: DatoveTypyPrimitivni - Zde je to jasné, jméno zdrojové třídy, ve které se metoda nachází
- Method: vypisBoolean - opět naprosto jasné, jedná se o jméno metody
- Signature: (Z)V - toto je nejzajímavější část, specifikuje její vstupní parametry a návratový typ metody. V našem konkrétním případě je metoda typu void a tudíž návratový parametr je "V" a vstupní parametr je boolean "(Z)"
/*
* Class: DatoveTypyPrimitivni
* Method: ziskejFloat
* Signature: ()F
*/
- Class: DatoveTypyPrimitivni - jméno zdrojové třídy, ve které se metoda nachází
- Method: ziskejFloat - jedná se o jméno metody
- Signature: ()F - V tomto konkrétním případě je návratový typ typu Float "F" a nemá žádný vstupní parametr "()"
Java typy | Označení typu |
---|---|
boolean | Z |
char | C |
byte | B |
short | S |
int | I |
long | J |
float | F |
double | D |
void | V |
Je pochopitelné, že toto je jen základní popis v případě jednoho parametru. V případě metod s více parametry s primitivními datovými typy je řešením jejich kombinace. Sami vidíte, že návrh od programátorů JNI je velmi logický.
native int vystupInt2(int hodnota2,int hodnota3); /* Signature: (II)I */ native void vlozHodnotu(double cisDouble,float cisFloat,int cisInt); /* Signature: (DFI)V */
Nyní si ukážeme jak vypadá zdrojový kód samotné sdílené knihovny vycházející ze zveřejněného header souboru.
#include <jni.h> #include <stdio.h> #include "primitivni.h" JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisBoolean(JNIEnv *env, jobject obj, jboolean bool){ printf("Zde je vypsan dany boolean : %d \n",bool); jboolean boolea = JNI_TRUE; printf("Zde je vypsan dany boolean : %d \n",boolea); } JNIEXPORT jboolean JNICALL Java_DatoveTypyPrimitivni_ziskejBoolean(JNIEnv *env, jobject obj){ jboolean boolea = JNI_FALSE; return boolea; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisByte(JNIEnv *env, jobject obj, jbyte bajt){ printf("Zde je vypsan dany byte : %d \n",bajt); jbyte hodnota = 55; printf("Zde je vypsan dany byte : %d \n",hodnota); } JNIEXPORT jbyte JNICALL Java_DatoveTypyPrimitivni_ziskejByte(JNIEnv *env, jobject obj){ jbyte hodnota = 22; return hodnota; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_vypisZnak(JNIEnv *env, jobject obj, jchar znak){ printf("Zde je vypsan dany znak : %c \n",znak); char zna ='C'; jchar znakk ='D'; printf("Zde je vypsan dany znak : %c \n",zna); printf("Zde je vypsan dany znak : %c \n",znakk); } JNIEXPORT jchar JNICALL Java_DatoveTypyPrimitivni_ziskejZnak(JNIEnv *env, jobject obj){ char znakC ='X'; jchar znakJ = znakC; return znakJ; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavShort(JNIEnv *env, jobject obj, jshort shortik){ printf("Zde je vypsan dany Short : %d \n",shortik); short cislo = 4561; printf("Zde je vypsan dany Short : %d \n",cislo); } JNIEXPORT jshort JNICALL Java_DatoveTypyPrimitivni_ziskejShort(JNIEnv *env, jobject obj){ unsigned short cislo = 56451; printf("Zde je vypsan mezi Short : %d \n",cislo); jshort ziskejShort = cislo; printf("Zde je vypsan mezi Short : %d \n",ziskejShort); return ziskejShort; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavInt(JNIEnv *env, jobject obj, jint integer){ printf("Zde je vypsan dany Integer : %d \n",integer); } JNIEXPORT jint JNICALL Java_DatoveTypyPrimitivni_ziskejInt(JNIEnv *env, jobject obj){ jint hodnota = 45678; return hodnota; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavLont(JNIEnv *env, jobject obj, jlong longer){ printf("Zde je vypsan dany Long : %d \n",longer); long hodnota1 = 456123; long hodnota2 = 7844456; printf("Vypsan vysledek : %d \n",(hodnota1+hodnota2)); } JNIEXPORT jlong JNICALL Java_DatoveTypyPrimitivni_ziskejLong(JNIEnv *env, jobject obj){ jlong cisloLong = 456785156; return cisloLong; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavFloat(JNIEnv *env, jobject obj, jfloat flot){ printf("Zde je vypsan dany float : %d \n",flot); float cislo1 = 784.657; float cislo2 = 46.789; printf("Vypsan vysledek : %d \n",(cislo1/cislo2)); } JNIEXPORT jfloat JNICALL Java_DatoveTypyPrimitivni_ziskejFloat(JNIEnv *env, jobject obj){ jfloat back = 76546.8876; return back; } JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavDouble(JNIEnv *env, jobject obj, jdouble doub){ printf("Zde je vypsan dany double : %d \n",doub); double hodno1 = 46657.657; double hodno2 = 466333.654; printf("Vypsan vysledek : %d \n",(hodno1+hodno2)); } JNIEXPORT jdouble JNICALL Java_DatoveTypyPrimitivni_ziskejDouble(JNIEnv *env, jobject obj){ jdouble cisloDouble =45667.358; return cisloDouble; }
Konečně si probereme vstupní parametry JNI metod:
/* Vychozi nativni metoda v interpretované části */ private native void nastavDouble(double hodnota); /* Hlavičkový soubor(Header File) - Signature: (D)V */ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavDouble(JNIEnv *, jobject, jdouble) /* Zdrojový soubor (Source File)*/ JNIEXPORT void JNICALL Java_DatoveTypyPrimitivni_nastavDouble(JNIEnv *env, jobject obj, jdouble doub)
- JNIEnv *env - Jedná se o parametr(odkaz) pro rozhraní JNI, které obsahuje metody jenž jsou nám přes daný parametr zpřístupněny
- jobject obj - trochu problematické, ale nejbližší definice je, že se jedná o objekt, který metodu volá. Umožňuje nám pracovat v JNI s objektem, jenž se nachází a byl vytvořen v interpretované části programu
- jdouble doub - standardní parametry metody, zde konkrétně typu double
V příští lekci, JNI - Pole primitivních datových typů, si vyzkoušíme práci s poli různých typů.