Narzędzia użytkownika

Narzędzia witryny


jni

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Previous revision
Next revision
Previous revision
jni [2008/04/13 00:37]
chappaai
jni [2008/04/16 23:55] (aktualna)
chappaai
Linia 1: Linia 1:
 ====== Java JNI i C++ ====== ====== Java JNI i C++ ======
 +Autor : Łukasz Mosdorf G1ISI 
 + ​--- ​
 +//​[[L.Mosdorf[eeeet]stud.elka.pw.edu.pl|Łukasz Mosdorf]] 2008/04/13 01:05//
  
-Ta strona zawiera prosty przykład zastosowania Java Native Interface. Technologia ta pozwala łączyć kod Javy z kodem pisanym ​pisanym w językach specyficznych dla danej platformy. Potrzeba łączenia Javy z C++ zachodzi np gdy +Ta strona zawiera prosty przykład zastosowania Java Native Interface. Technologia ta pozwala łączyć kod Javy z kodem pisanym w językach specyficznych dla danej platformy. Potrzeba łączenia Javy z C++ zachodzi np gdy 
   * maszyna wirtualna nie jest w stanie zapewnić nam wystarczającej szybkości obliczeń   * maszyna wirtualna nie jest w stanie zapewnić nam wystarczającej szybkości obliczeń
   * Chcemy połączyć aplikację javy z juz istniejącym kawałkiem oprogramowania napisanego w C/C++   * Chcemy połączyć aplikację javy z juz istniejącym kawałkiem oprogramowania napisanego w C/C++
Linia 8: Linia 11:
   * Utworzyć klasę (Javaclass.java),​ która deklaruje metodę natywną   * Utworzyć klasę (Javaclass.java),​ która deklaruje metodę natywną
   * skompilowac tę klasę za pomocą polecenia '​javac'​ i w ten sposób otrzymać Javaclass.class   * skompilowac tę klasę za pomocą polecenia '​javac'​ i w ten sposób otrzymać Javaclass.class
-  * uzyc javah -jni aby otrzymac plik naglowkowy, w oparciu o ktory napiszemy kod w C+++  * uzyc javah -jni aby otrzymac plik naglowkowy, w oparciu o który ​napiszemy kod w C++ 
 +  * napisać kod w C++  
 +  * skompilować kod do postaci biblioteki (*.dll pod Windows, *.so pod Solarisem) 
 +  * uruchomić program Javaclass 
 + 
 +Przykładowa seria poleceń potrzebna do kompilacji przykładu na platformie Windows: 
 + 
 +<code cpp> 
 +javac .\jni_pkg\Jni.java 
 +javah -jni jni_pkg.Jni 
 +cl -I "​c:​\Program Files\Microsoft Visual Studio 9.0\VC\include"​ -I "​c:​\j2sdk1.4.2_17\include  
 +-I"​c:​\j2sdk1.4.2_17\include\win32"​ -LD jni_pkg_Jni.cpp -FeJni_lib.dll''​ 
 +</​code>​ 
 + 
 +Jeżeli powyższe polecenia nie dzialaja, należy dodać odpowienie ścieżki do zmiennej srodowiska Windows -  PATH. 
 +Polecenie cl polecam uruchamiac z konsoli Visual Studio - nie mamy wtedy problemów z wskazywaniem lokalizacji dodatkowych plików nagłówkowych i bibliotek. 
 + 
 +===== Kod Java ===== 
 +Kod zawiera kilka deklaracji przykladowych metod natywnych które sa następnie w nim wykorzystywane. 
 + 
 +<code java> 
 +/** 
 + * @author Lukasz Mosdorf G1ISI 
 + */ 
 +/**  
 + * Program ilustrujący Zastosowanie JNI - Java Native Interface.  
 + * Kod wywołuje kilka natywnych metod napisanych w cpp 
 + */ 
 +package jni_pkg; 
 + 
 +public class Jni { 
 +     
 +    public int myInt = 10; 
 +    public static String mystring ​ = "JNI example";​ 
 +    public int[] intArray; 
 +    private static native ​ void native_call(); ​ // sample native call  
 +    private static native ​  ​String change_string(String arg); 
 +    private native int sumArray(int[] arr); 
 +    private native int initCppObj();​ 
 +    private native int deleteCppObj();​ 
 +    private native int changeCppObjField(int a); 
 +    private native void callMe(); 
 +    public int cppObjPtr;​ 
 +    private void callback() 
 +    { 
 +        System.out.println("​Java wywolana z cpp"​); ​        
 +    } 
 +    //Static- wywolywane na saym poczatku 
 +    static { 
 +    System.loadLibrary("​Jni_lib"​);​ 
 +    } 
 +      
 +    public static void main(String[] args)  
 +    { 
 +        Jni jni = new Jni(); 
 +        int arr[] = new int[10]; 
 +        
 +        //​wywołanie metody natywnej, która zmienia podany obiekt String 
 +        String input = jni.change_string("​String wyslany do metody natywnej"​);​ 
 +        System.out.println("​Dostano w Javie zmieniony string: "+ input); 
 +         
 +        //​Zapełnienie tablicy danymi i wywołanie natywnje funkcji sumującej 
 +        for (int i = 0; i < 10; i++) { 
 +            arr[i] = i; 
 +        } 
 +        int sum = jni.sumArray(arr);​ 
 +        System.out.println("​Suma tablicy zwrocona z metody natywnej = " + sum); 
 +         
 +        //​inicjalizaja obiektu lol, wskaznik przechowywany w cppObjPtr 
 +        jni.initCppObj();​ 
 +        System.out.println("​Obiekt lol zaalokowany:​ "+ jni.cppObjPtr);​ 
 +        //​Wywołanie metody obiektu uprzednio zaalokowanego,​  
 +        //ktora zmienia wartosc jego pola 
 +        jni.changeCppObjField(15);​ 
 +        //wołanie metody która wywołuje motodę obiektu wołającego 
 +        jni.callMe();​ 
 +        jni.deleteCppObj();​ 
 +        System.out.println("​Obiekt lol usuniety, ptr: "+ jni.cppObjPtr);​ 
 +    } 
 +
 +</​code>​ 
 + 
 + 
 + 
 +===== Kod Cpp ===== 
 + 
 +Poniżej przedstawiono plik nagłówkowy wygenerowany automatycznie przy uzyciu polecenia javah -jni jni_pkg.Jni. 
 + 
 +<code cpp> 
 +/*Lukasz Mosdorf G1ISI 
 +*Plik "​jni_pkg_Jni.h"​ generowany  
 +*przy wywolaniu polecenia javah -jni jni_pkg.Jni 
 +*/ 
 + 
 +/* DO NOT EDIT THIS FILE - it is machine generated */ 
 +#include <​jni.h>​ 
 +/* Header for class jni_pkg_Jni */ 
 + 
 +#ifndef _Included_jni_pkg_Jni 
 +#define _Included_jni_pkg_Jni 
 +#ifdef __cplusplus 
 +extern "​C"​ { 
 +#endif 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   native_call 
 + * Signature: ()V 
 + */ 
 +JNIEXPORT void JNICALL Java_jni_1pkg_Jni_native_1call 
 +  (JNIEnv *, jclass); 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   change_string 
 + * Signature: (Ljava/​lang/​String;​)Ljava/​lang/​String;​ 
 + */ 
 +JNIEXPORT jstring JNICALL Java_jni_1pkg_Jni_change_1string 
 +  (JNIEnv *, jclass, jstring); 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   sumArray 
 + * Signature: ([I)I 
 + */ 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_sumArray 
 +  (JNIEnv *, jobject, jintArray);​ 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   initCppObj 
 + * Signature: ()I 
 + */ 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_initCppObj 
 +  (JNIEnv *, jobject); 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   deleteCppObj 
 + * Signature: ()I 
 + */ 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_deleteCppObj 
 +  (JNIEnv *, jobject); 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   changeCppObjField 
 + * Signature: (I)I 
 + */ 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_changeCppObjField 
 +  (JNIEnv *, jobject, jint); 
 + 
 +/* 
 + * Class: ​    ​jni_pkg_Jni 
 + * Method: ​   callMe 
 + * Signature: ()V 
 + */ 
 +JNIEXPORT void JNICALL Java_jni_1pkg_Jni_callMe 
 +  (JNIEnv *, jobject); 
 + 
 +#ifdef __cplusplus 
 +
 +#endif 
 +#endif 
 + 
 + 
 + 
 +</​code>​ 
 + 
 +Ciała metod natywnych znajdują się w pliku cpp pzedstawionym poniżej: 
 + 
 +<code cpp> 
 +/** 
 +*Łukasz Mosdorf G1ISI 
 +*Plik "​jni_pkg_Jni.cpp"​ zawierajacy definicje klasy i kilka metod natywnych  
 +*wolanych z Javy. Załączamy plik "​jni_pkg_Jni.h"​ generowany  
 +*przy wywolaniu polecenia javah -jni jni_pkg.Jni 
 +*/ 
 + 
 + 
 + 
 +#include "​jni_pkg_Jni.h"​ 
 +#include <​iostream>​ 
 +#include <​jni.h>​ 
 +using namespace std; 
 + 
 +class Lol 
 +
 +private: 
 + int i; 
 +public: 
 + void changei(int arg) 
 +
 + i=arg; 
 + cout<<"​W obiekcie Lol, zmieniono wartosc i na: "<<​i<<​endl;​ 
 +
 +}; 
 + 
 +//Prosta metoda cpp wywolywana z poziomu javy 
 +//Przykład podstawowej składni metody napisanej w C++ (C) i wołanej z Javy 
 +JNIEXPORT void JNICALL Java_jni_1pkg_Jni_native_1call (JNIEnv * env, jclass cls) 
 +
 + cout<<"​Najprostsza metoda c++ wywołana z javy !!"<<​endl;​  
 +
 + 
 +//Metoda zmieniajaca wartosc Stringa Javy podanego jako argument  
 +JNIEXPORT jstring JNICALL Java_jni_1pkg_Jni_change_1string (JNIEnv * env, jclass jCl, jstring inStr) 
 +
 + char buf[128]; 
 +    const char *str; 
 + 
 + /* Przeksztalcamy String javowy na ciąg bajtów*/ 
 + str = env->​GetStringUTFChars(inStr,​ NULL); 
 +    if (str == NULL) { 
 +        return NULL; // OutOfMemoryError juz rzucony 
 +    } 
 + 
 + printf("​W metodzie cpp String: %s \n", str); 
 + //​Zwalniamy obiekt aby mogl sie nim zajac juz Garbage Collector 
 + env->​ReleaseStringUTFChars(inStr,​ str); 
 +    //Zakladamy ze uzytkownik nie wpisze wiecej niz 127 znakow... 
 +    cout<<"​Wprowadz nowego Stringa"<<​endl;​ 
 + scanf("​%s",​ buf); 
 +     
 + return env->​NewStringUTF(buf);​ 
 +
 + 
 +//Prosta metoda sumująca tablice intów 10-elementową podana z poziomy Javy jako argument 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_sumArray(JNIEnv *env, jobject obj, jintArray arr) 
 +
 +    jint buf[10]; 
 +    jint i, sum = 0; 
 + //​pobieramy tablice 
 +    env->​GetIntArrayRegion(arr,​ 0, 10, buf); 
 + //​sumujemy 
 +    for (i = 0; i < 10; i++) { 
 +        sum += buf[i]; 
 +    } 
 +    return sum; 
 +
 + 
 +/*Metoda inicjalizująca obiekt lol, i zapisujaca miejsce jego alokacji w pamieci  
 +* w polu cppObjPtr obiektu który tę metodę wywolal. 
 +*/ 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_initCppObj (JNIEnv *env , jobject jObj) 
 +
 + jfieldID fid;  //​magazynujemy id pola klasy javowej 
 +  
 + /* pobieramy referencje na klase obiektu jObj */ 
 +    jclass cls = env->​GetObjectClass(jObj);​ 
 + 
 + /* Pobieramy ID pola klasy*/ 
 + fid = env->​GetFieldID(cls,​ "​cppObjPtr",​ "​I"​);​ 
 +    if (fid == NULL) { 
 +        return (jint)1; /* nie udalo sie zdobyc id pola */ 
 +    } 
 +  
 + 
 + jint ptr = env->​GetIntField(jObj,​ fid); 
 + cout<<"​poczatkowa wartosc wskaznika to: "<<​(int)ptr<<​endl;​ 
 + 
 + Lol* lol = new Lol(); 
 + if (!lol) 
 +
 + return (jint)1; //nie udalo sie zaalokowac 
 +
 + //zwracamy wskaznik zaalokowanego obiektu 
 + env->​SetIntField(jObj,​ fid, (jint)lol);​ 
 + 
 + return (jint)0; 
 +
 + 
 + 
 +//Prosta metoda wywołująca metodę obiektu lol (uprzednio zaalokowanego). Metoda zmienia wartość pola obiektu 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_changeCppObjField (JNIEnv* env, jobject jObj, jint k) 
 +
 + /​*pzrechowujemy id pola klasy javowej*/ 
 + jfieldID fid;   
 +  
 + /* pobieramy referencje na klase obiektu jObj */ 
 +    jclass cls = env->​GetObjectClass(jObj);​ 
 + 
 + /* pobieramy field ID*/ 
 + fid = env->​GetFieldID(cls,​ "​cppObjPtr",​ "​I"​);​ 
 +    if (fid == NULL) { 
 +        return (jint)1; /* nie udalo sie zdobyc id pola */ 
 +    } 
 + /​*Pobieramy wskaznik na nasz obiekt (zapisany w polu klasy wywolujacej metode)*/ 
 + jint ptr = env->​GetIntField(jObj,​ fid); 
 + 
 + Lol* lol = (Lol*)ptr;​ 
 + /​*wywolujemy metodę obiektu lol*/ 
 + lol->​changei(k);​ 
 + return 0; 
 +
 + 
 +//Metoda realizujaca tzw CALLBACK, czyli wywołanie metody nalezacej do obiektu javy 
 +JNIEXPORT void JNICALL Java_jni_1pkg_Jni_callMe (JNIEnv * env, jobject jObj) 
 +
 + jclass cls = env->​GetObjectClass(jObj);​ 
 + //​pobieramy ID metody 
 +    jmethodID mid = env->​GetMethodID(cls,​ "​callback",​ "​()V"​);​ 
 +    if (mid == NULL) { 
 +        return; // nie znaleziono metody 
 +    } 
 +    cout<<"​W C++, przed Callback'​iem"<<​endl;​ 
 +    env->​CallVoidMethod(jObj,​ mid); 
 + cout<<"​W C++, po Callbacku"<<​endl;​ 
 +
 + 
 +JNIEXPORT jint JNICALL Java_jni_1pkg_Jni_deleteCppObj (JNIEnv * env , jobject jObj) 
 +
 + jfieldID fid;  //​magazynujemy id pola klasy javowej 
 +  
 + /* pobieramy referencje na klase obiektu jObj */ 
 +    jclass cls = env->​GetObjectClass(jObj);​ 
 + 
 + /* Pobieramy ID pola klasy*/ 
 + fid = env->​GetFieldID(cls,​ "​cppObjPtr",​ "​I"​);​ 
 +        if (fid == NULL) { 
 +        return (jint)1; /* nie udalo sie zdobyc id pola */ 
 +        } 
 +  
 + 
 + jint ptr = env->​GetIntField(jObj,​ fid); 
 + cout<<"​poczatkowa wartosc wskaznika na obiekt ktory usuwamy to: "<<​(int)ptr<<​endl;​ 
 + 
 + Lol* lol = reinterpret_cast<​Lol*>​(ptr);​ 
 +  
 + delete lol; 
 + //zwracamy wskaznik zaalokowanego obiektu 
 + env->​SetIntField(jObj,​ fid, (jint)0); 
 + 
 + return (jint)0; 
 + 
 + 
 +
 +</​code>​ 
  
  
jni.1208039820.txt.gz · ostatnio zmienione: 2008/04/13 00:37 przez chappaai