Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

8. diel - JNI - Pole primitívnych dátových typov

V minulom tutoriále o Java Native Interface sme si uviedli existujúci primitívne dátové typy a ako sa s nimi pracuje. Dnes si preberieme pole (Arrays) a vyskúšame si ich na príklade.

Pole primitívnych dátových typov

Práca s poľami je veľmi jednoduchá. Už nebudem krok po kroku vytvárať príklad, dúfam, že to už viete z predchádzajúcich dielov. Tu si ukážeme ako sa s takýmito poľami pracuje. Pozrime sa aká poľa môžeme v JNI používať:

Java typy - pole Natívne 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 uvedenom príklade si vytvoríme 3 statické polia, z ktorých sú dve typu int a jedno typu double. Príklad obsahuje štyri natívne metódy. Dve pracujú s int poli a dve s double poli ako vstupnými parametrami metód. Zostávajúce dve metódy majú dané pole ako návratový typ. Čo konkrétne budú robiť si preberieme neskôr, aj keď z názvu to dá vydedukovať. Práca s poľami vyšších rádov (viacrozmerné pole - dvoch, troch, štyroch, ...) 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");
    }
}
Doma, trieda pre prácu s poľami v JNI - JNI - Java Native Interface

Teraz si vykonáme vytvorenie hlavičkového súboru.

header File - JNI - Java Native Interface

Tu 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

Teraz si preberieme čo znamená opis v header file pri jednotlivých metód. napr.

/*
 * Class:     ProjektJNIPole
 * Method:    posliPoleInt
 * Signature: ([I[I)V
 */
  • Class: ProjektJNIPole - tu to je jasné, meno zdrojovej triedy, v ktorej sa metóda nachádza
  • Method: posliPoleInt - opäť úplne jasné, jedná sa o meno metódy
  • Signature: ([I [I) V - toto je najzaujímavejšia časť, špecifikuje jej vstupné parametre a návratový typ metódy. V našom konkrétnom prípade je metóda typu void a teda návratový parameter je "V" a vstupný parameter sú dve polia int "([I [I)"
/*
 * Class:     ProjektJNIPole
 * Method:    ziskejPoleDouble
 * Signature: ()[D
 */
  • Class: ProjektJNIPole - meno zdrojové triedy, v ktorej sa metóda nachádza
  • Method: ziskejPoleDouble - jedná sa o meno metódy
  • Signature: () [D - V tomto konkrétnom prípade je návratový typ poľa double "[D" a nemá žiadny vstupný parameter "()".
Java polia typy JNI označenie poľa typov
boolean [] [Z
char [] [C
byte [] [B
short [] [S
int [] [I
long [] [J
float [] [F
double [] [D
void V
V prípade metód s viacerými parametrami s viacrozmernými poliami primitívnych dátových typov je riešením ich kombinácie.
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 */

Teraz si ukážeme ako vyzerá zdrojový kód samotnej zdieľané knižnice vychádzajúci zo zverejneného header súboru:

#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;
}

Metóda posliPoleInt: Prvá metóda nemá návratový typ. Vstupnými parametrami sú dve polia Integer. Ako prvý zistíme hodnotu veľkosti vstupujúcich polí. Potom prenesieme pole jintArray do poľa jint. S poľom jint sa bude pracovať. Ak sa veľkosti polí budú rovnať, potom sa obe polia spočítajú. Inak sa metóda ukončí. A nakoniec sa pole pre kontrolu vypíše.

Metóda ziskejPoleInt: Druhá metóda metóda má návratový typ poľa Integer. Naplním jint pole hodnotami. Ako ďalšie vytvoríme objekt jintArray a definujeme jeho veľkosť. Nakopírujeme pole s hodnotami do vzniknutého objektu jintArray. A potom dané pole nastavíme ako návratový typ.

Metóda posliPoleDouble: Tretia metóda nemá návratový typ. Vstupujúcim poľom je pole double, v JNI známu ako jdoubleArray. Zistíme veľkosť poľa, prenesieme jdoubleArray do poľa jdouble a potom vykonáme výpis daného poľa.

Metóda ziskejPoleDouble: Štvrtá metóda má návratový typ poľa double. Najskôr si vyrobíme štandardné pole double v syntaxi C. Toto pole prenesieme do JNI poľa typov jdouble. Ako ďalšie vytvoríme objekt jdoubleArray a definujeme jeho veľkosť. Nakopírujeme pole s hodnotami do vzniknutého objektu jdoubleArray. A potom dané pole nastavíme ako návratový typ.

Prevedieme nastavenie kompilátora a linker - špecifikujeme x86_64-w64-mingw32-gcc. Ako ďalší krok nasleduje build knižnice.

Build natívne knižnice v Jave - JNI - Java Native Interface

Po zbuildování knižnice do * .dll sa prepneme späť na Java perspektívu. Presunieme zdieľanú knižnicu do iného adresára, napr. \ Src \, a vykonáme úpravu východiskovej Java triedy. Načítanie knižnice tentoraz umiestnime priamo do main metódy a nedáme do výnimky.

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ýsledok:

spustenie DLL - JNI - Java Native Interface

 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 511x (103.11 kB)

 

Predchádzajúci článok
JNI - Primitívne dátové typy
Všetky články v sekcii
JNI - Java Native Interface
Preskočiť článok
(neodporúčame)
JNI - Práca s objektom
Článok pre vás napísal Robert Michalovič
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
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