Lekce 8 - JNI - Pole primitivních datových typů
V minulém tutoriálu o Java Native Interface, JNI - Primitivní datové typy, jsme si uvedli existující primitivní datové typy a jak se s nimi pracuje.
Dnes si probereme pole (arrays) a vyzkoušíme si je na příkladu.
Pole primitivních datových typů
Práce s poli je velmi jednoduchá. Už nebudu krok po kroku vytvářet příklad, doufám, že to již umíte z předchozích dílů. Zde si ukážeme jak se s takovými poli pracuje. Podívejme se jaká pole můžeme v JNI používat:
Java typy - pole | Nativní JNI typy - pole | C typy - pole |
---|---|---|
boolean [] | jbooleanArray | neobsahuje |
char [] | jcharArray | char [] |
byte [] | jbyteArray | neobsahuje |
short | jshortArray | short [] |
long [] | jlongArray | long [] |
int [] | jintArray | int [] |
float [] | jfloatArray | float [] |
double [] | jdoubleArray | double [] |
V uvedeném příkladu si vytvoříme 3 statická pole, z nichž jsou dvě typu int a jedno typu double. Příklad obsahuje čtyři nativní metody. Dvě pracují s int poli a dvě s double poli jako vstupními parametry metod. Zbývající dvě metody mají dané pole jako návratový typ. Co konkrétně budou dělat si probereme později, i když z názvu to lze vydedukovat. Práce s poli vyšších řádů (vícerozměrná pole - dvou,tří,čtyř,...) je analogická.
public class ProjektJNIPole { private static int [] poleI1 = {5,6,12,35}; private static int [] poleI2 = {1,2,3,4}; private static double [] poleD1 = {35.56,8987.554,99.785,123.567}; native void posliPoleInt(int [] poleI1,int poleI2 []); native int [] ziskejPoleInt(); native void posliPoleDouble(double [] poleD1); native double [] ziskejPoleDouble(); public static void main(String[] args) { System.out.println("Testovaci vypis"); } }

Nyní si provedeme vytvoření hlavičkového souboru.

Zde je vygenerovaný header file:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class ProjektJNIPole */ #ifndef _Included_ProjektJNIPole #define _Included_ProjektJNIPole #ifdef __cplusplus extern "C" { #endif /* * Class: ProjektJNIPole * Method: posliPoleInt * Signature: ([I[I)V */ JNIEXPORT void JNICALL Java_ProjektJNIPole_posliPoleInt (JNIEnv *, jobject, jintArray, jintArray); /* * Class: ProjektJNIPole * Method: ziskejPoleInt * Signature: ()[I */ JNIEXPORT jintArray JNICALL Java_ProjektJNIPole_ziskejPoleInt (JNIEnv *, jobject); /* * Class: ProjektJNIPole * Method: posliPoleDouble * Signature: ([D)V */ JNIEXPORT void JNICALL Java_ProjektJNIPole_posliPoleDouble (JNIEnv *, jobject, jdoubleArray); /* * Class: ProjektJNIPole * Method: ziskejPoleDouble * Signature: ()[D */ JNIEXPORT jdoubleArray JNICALL Java_ProjektJNIPole_ziskejPoleDouble (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
Nyní si probereme co znamená popis v header file u jednotlivých metod. např.
/*
* Class: ProjektJNIPole
* Method: posliPoleInt
* Signature: ([I[I)V
*/
- Class: ProjektJNIPole - zde to je jasné, jméno zdrojové třídy, ve které se metoda nachází
- Method: posliPoleInt - opět naprosto jasné, jedná se o jméno metody
- Signature: ([I[I)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 jsou dvě pole int "([I[I)"
/*
* Class: ProjektJNIPole
* Method: ziskejPoleDouble
* Signature: ()[D
*/
- Class: ProjektJNIPole - jméno zdrojové třídy, ve které se metoda nachází
- Method: ziskejPoleDouble - jedná se o jméno metody
- Signature: ()[D - V tomto konkrétním případě je návratový typ pole double "[D" a nemá žádný vstupní parametr "()".
Java pole typy | JNI označení pole typů |
---|---|
boolean [] | [Z |
char [] | [C |
byte [] | [B |
short [] | [S |
int [] | [I |
long [] | [J |
float [] | [F |
double [] | [D |
void | V |
V případě metod s více parametry s vícerozměrnými poli primitivních datových typů je řešením jejich kombinace.
native byte [] vystupInt2(int [] pole1,double [] vektorDouble); /* Signature: ([I[D)[B */ native char [] vlozHodnotu(double [][] maticeDouble,float [][][] matice3D,long [][] maticeLong); /* Signature: ([[D[[[F[[J)[C */
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 "ProjektJNIPole.h" #define MAX 5 JNIEXPORT void JNICALL Java_ProjektJNIPole_posliPoleInt(JNIEnv *env, jobject obj, jintArray poleInt1, jintArray poleInt2){ // zjistime velikost poli jsize velikostPole1 = (*env)->GetArrayLength(env,poleInt1); jsize velikostPole2 = (*env)->GetArrayLength(env,poleInt2); // preneseme vstupni pole do poli jint jint *poleINT1 = (*env)->GetIntArrayElements(env,poleInt1,NULL); jint *poleINT2 = (*env)->GetIntArrayElements(env,poleInt2,NULL); int i; int poleInt [velikostPole1]; if(velikostPole1 == velikostPole2) { for(i=0;i<velikostPole1;i++) { poleInt[i] = poleINT1[i]+poleINT2[i]; } } else { printf("Pole se nerovnaji - ukonceni nativni metody"); return ; } printf("Provedeme vypis pole jenz je soucet vstupnich poli - metoda posliPoleInt \n"); for(i=0;i<velikostPole1;i++){ printf("index pole [%d] hodnota= %d\n",i,poleInt[i]); } } JNIEXPORT jintArray JNICALL Java_ProjektJNIPole_ziskejPoleInt(JNIEnv *env, jobject obj){ // z duvodu zjednoduseni pouzijeme velikost pole definici MAX jint poleI [] = {56,68,-456,216,66}; jintArray poleInt = (*env)->NewIntArray(env,MAX); (*env)->SetIntArrayRegion(env,poleInt,0,MAX,poleI); return poleInt; } JNIEXPORT void JNICALL Java_ProjektJNIPole_posliPoleDouble(JNIEnv *env, jobject obj, jdoubleArray poleDouble){ // zjistime velikost poli jsize velikostPole1 = (*env)->GetArrayLength(env,poleDouble); // preneseme vstupni pole do poli jdouble jdouble *poleDOUBLE1 = (*env)->GetDoubleArrayElements(env,poleDouble,NULL); int i; for(i=0;i<velikostPole1;i++){ printf("index pole [%d] hodnota= %f\n",i,poleDOUBLE1[i]); } } JNIEXPORT jdoubleArray JNICALL Java_ProjektJNIPole_ziskejPoleDouble(JNIEnv *env, jobject obj){ // vytvorime double pole viz. C double poleD [MAX]; poleD[0]=-34.4556; poleD[1]=79635.65; poleD[2]=123.455; poleD[3]=-985.456; poleD[4]=-22.789; // vytvorime jdouble pole viz. JNI jdouble pole [MAX]; int i; for(i=0;i<MAX;i++){ pole[i]=(jdouble)poleD[i]; } // vytvorime JNI pole jdoubleArray poleDouble = (*env)->NewDoubleArray(env,MAX); // naplnime JNI pole daty (*env)->SetDoubleArrayRegion(env,poleDouble,0,MAX,pole); return poleDouble; }
Metoda posliPoleInt : První metoda nemá návratový typ. Vstupními parametry jsou dvě pole integerů. Jako první zjistíme hodnotu velikosti vstupujících polí. Poté přeneseme pole jintArray do pole jint. S polem jint se bude pracovat. Pokud se velikosti polí budou rovnat, pak se obě pole sečtou. Jinak se metoda ukončí. A nakonec se pole pro kontrolu vypíše.
Metoda ziskejPoleInt : Druhá metoda metoda má návratový typ pole integerů. Naplnime jint pole hodnotami. Jako další vytvoříme objekt jintArray a definujeme jeho velikost. Nakopírujeme pole s hodnotami do vzniklého objektu jintArray. A poté dané pole nastavíme jako návratový typ.
Metoda posliPoleDouble : Třetí metoda nemá návratový typ. Vstupujícím polem je pole double, v JNI znamé jako jdoubleArray. Zjistíme velikost pole, přeneseme jdoubleArray do pole jdouble a poté provedeme výpis daného pole.
Metoda ziskejPoleDouble : Čtvrtá metoda má návratový typ pole double. Nejdříve si vyrobíme standardní pole double v syntaxi C. Toto pole přeneseme do JNI pole typů jdouble. Jako další vytvoříme objekt jdoubleArray a definujeme jeho velikost. Nakopírujeme pole s hodnotami do vzniklého objektu jdoubleArray. A poté dané pole nastavíme jako návratový typ.
Provedeme nastavení kompilátoru a linkeru - specifikujeme
x86_64-w64-mingw32-gcc
. Jako další krok následuje build
knihovny.

Po zbuildování knihovny do *.dll se přepneme zpět na Java perspektivu. Přesuneme sdílenou knihovnu do jiného adresáře, např. \src\, a provedeme úpravu výchozí Java třídy. Načítání knihovny tentokrát umístíme přímo do main metody a nedáme do výjimky.
public class ProjektJNIPole { private static int [] poleI1 = {5,6,12,35}; private static int [] poleI2 = {1,2,3,4}; private static double [] poleD1 = {35.56,8987.554,99.785,123.567}; native void posliPoleInt(int [] poleI1,int poleI2 []); native int [] ziskejPoleInt(); native void posliPoleDouble(double [] poleD1); native double [] ziskejPoleDouble(); public static void main(String[] args) { System.out.println("Testovaci vypis"); System.loadLibrary("src/libProjektJNIPole"); ProjektJNIPole program = new ProjektJNIPole(); /** Provedem zavolani metod s datovymi typy int **/ program.posliPoleInt(poleI1, poleI2); int [] poleIntNative = program.ziskejPoleInt(); for(int c : poleIntNative) { System.out.println("Nativni pole (int)\t"+c); } /** Provedem zavolani metod s datovymi typy double **/ program.posliPoleDouble(poleD1); double [] poleDoubleNative = program.ziskejPoleDouble(); for(double c:poleDoubleNative) { System.out.println("Nativni pole (double)\t"+c); } } }
Výsledek:

V další lekci, JNI - Práce s objektem, započneme práci s objekty.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkamiStaženo 549x (103.11 kB)