8. díl - JNI - Pole primitivních datových typů

Java Pro pokročilé JNI JNI - Pole primitivních datových typů

V minulém tutoriálu o Java Native Interface 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

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

Header File

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ě

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

 

Stáhnout

Staženo 41x (103.11 kB)

 

  Aktivity (6)

Článek pro vás napsal Robert Michalovič
Avatar
viz. linkedin

Jak se ti líbí článek?
Celkem (1 hlasů) :
55555


 


Miniatura
Předchozí článek
JNI - Primitivní datové typy
Miniatura
Všechny články v sekci
JNI - Java Native Interface
Miniatura
Následující článek
JNI - Práce s objektem

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!