Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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");
    }
}
Vychozí třída pro práci s poli v JNI - JNI - Java Native Interface

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

Header File - JNI - Java Native Interface

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.

Build nativní knihovny v Javě - JNI - Java Native Interface

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:

Spuštení DLL - JNI - Java Native Interface

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ínkami

Staženo 470x (103.11 kB)

 

Předchozí článek
JNI - Primitivní datové typy
Všechny články v sekci
JNI - Java Native Interface
Přeskočit článek
(nedoporučujeme)
JNI - Práce s objektem
Článek pro vás napsal Robert Michalovič
Avatar
Uživatelské hodnocení:
1 hlasů
Programuji převážně v Javě SE,EE a trochu nativním C a CUDA. více viz.https://cz.linkedin.com/in/robert-michalovic
Aktivity