190 likes | 290 Views
Java mit eingebundenen (native) C-Programme. Vortrag: Rolf Heitzenröder am 29.6.2000. Warum JNI?. Java bietet eine Vielzahl von Möglichkeiten der Programmierung. Angefangen von graphischen Verschönern bis hin zur Netzwerk- und Serverprogrammierung.
E N D
Java mit eingebundenen(native) C-Programme Vortrag: Rolf Heitzenröder am 29.6.2000 EDV 1 - Java Native Interface
Warum JNI? • Java bietet eine Vielzahl von Möglichkeiten der Programmierung. Angefangen von graphischen Verschönern bis hin zur Netzwerk- und Serverprogrammierung. • Doch läßt sich in Zeit kritischen Anwendungen und bei evtl. Plattform spezifischer Programmierung eine Realisierung im normalen Java nicht realisieren. • Hier hilft das Java Native Interface (JNI) weiter. EDV 1 - Java Native Interface
Mit Hilfe von JNI kann in eine Javaklasse Nativer Code, also ein „Heimischer“ Programmcode eingebunden werden. • Damit werden die bereits existierenden Programme (z.B. in C geschriebene) nicht einfach unbrauchbar. Bei der Umstellung auf Java. • Auch bei dem vorhergehenden Punkt, einer Zeit kritischen Anwendung, liegt hier noch ein Vorteil in nativen Code. Er ist besser auf das bestehende Betriebssystem zu optimieren. Natürlich wird mit dem einfügen von nativen Code(C-Dateien) die portabilität von Java eingeschränkt. EDV 1 - Java Native Interface
Wie wird nun JNI angewendet? Um eine natives Programm nun auch in Java verwenden zu können muß in der Java Klasse eine Methode deklariert werden, bei der Methode wird mit dem native-Schlüsselwort festgelegt, daß es sich um eine Methode handelt, die in einer anderen Programmiersprache geschrieben ist. public native void displayMethode(); EDV 1 - Java Native Interface
Ein grober Überblick:1) Java Klasse mit Methode anfertigen. Diese Klasse deklariert die native Methode.2) Java Klasse compilieren (javac ...)3) Mit dieser Class-File wird nun die benötigte Header-Datei erzeugt (javah -jni Class-File)4) C-Programm schreiben.5) C-Programm mit der (mit javah) erzeugten Header-Datei compileren in eine (in WIN32) DLL-Datei.Fertig! EDV 1 - Java Native Interface
Native Methode deklarieren:public native void myMethode(); Da der Rumpf der Methode in C geschrieben wird muß die Methode „leer“ bleiben. Sie wird mit einem Semikolon abgeschlossen. Bibliothek laden:System.loadLibrary("LibName"); "LibName" ist der Dateiname unter der die DLL compiliert worden ist. Main-Methode:public static void main(String[] args) {new ClassName().myMethode();} EDV 1 - Java Native Interface
Hier das "alt" bekannte Hello-World-Programm (Java Seite): class HelloWorld { public native void displayHelloWorld(); static { System.laodLibrary("hello"); } public static void main(String[] args) { new HelloWorld().displayHelloWorld(); } Dieses Java Programm wird normal compilert. Mit der erzeugten Class-Datei wird nun die erforderliche Header-Datei, für unser C-Programm erzeugt. Dies geschieht mit "javah" und dem Parameter "-jni".javah -jni HelloWorld Zur Information: Die Header-Datei sieht folgendermaßen aus: EDV 1 - Java Native Interface
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h> /* Header for class HelloWorld */#ifndef _Included_HelloWorld#define _Included_HelloWorld #ifdef __cplusplusextern "C" {#endif /* * Class: HelloWorld * Method: displayHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject); #ifdef __cplusplus}#endif #endif Diese Datei wird automatisch mit "javah -jni" generiert. Im Javafile wurde hier nur eine native-Methode deklariert. Wird eine weitere benötig und in Java deklariert, ergänzt "javah" die h-Datei ... EDV 1 - Java Native Interface
mit den folgenden Zeilen: /* * Class: HelloWorld * Method: deutschHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_zweiteHelloWorld (JNIEnv *, jobject); usw. Diese Funktionen im Header-File besitzen zwei Parameter. JNIEnv* und jobject . "JNIEnv*" ist ein Interface Pointer und "jobjekt" ist ein Parameter der das aktuelle Objekt referenziert. Vergleichbar mit der "this" Variable in Java. In diesem Beispiel werden aber beide Parameter ignoriert. EDV 1 - Java Native Interface
Nun wird es Zeit sich um die Impementierung in C zu kümmern: "javah" hat eine sogenannte Signatur für die Methoden generiert:Java_HelloWorld_displayHelloWorld Im C-Code muß nun als Methode/Funktion die gleiche Signatur verwendet werden: Bsp: #include <jni.h>#include "HelloWorld.h"#include <stdio.h>JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld( JNIEnv *env, jobject jobj) { printf("Hello world!\n"); return;} "jni.h" stellt informationen bereit, die für das zusammen Spiel mit dem Java Runtime System von Bedeutung ist. Dieses Header-File muß immer im C-Code "included" sein. "hello.h" soll unser generiertes Header-File sein. EDV 1 - Java Native Interface
Nun passiert es auch, daß man Werte den Methoden übergeben muß. Auf Java Seite werden diese Varablen gewöhnlich wie in jeder Methode als Parameter angegeben. Auf C der Seite erhält man die Möglichkeit, alle primitiven Datentypen wie in Java anzugeben, nur mit einem "j" vorangestellt. EDV 1 - Java Native Interface
Übersicht der Datentypen: In C haben die primitiven Datentypen den gleichen Namen, nur mit einem j vorangestellt. • Java C Bits • --------------------------------------------- • boolean jboolean 8 • unsi gned • byte jbyte 8 • char jchar 16, • unsigned • short jshort 16 • int jint 32 • long jlong 64 • float jfloat 32 • double jdouble 64 • void void - EDV 1 - Java Native Interface
Java-Objekt C-Typ • -------------------------------------------------------------- • Object jobject repräsentiert alle Java-Objekte • Class jclass repräsentiert ein Klassenobjekt • String jstring • jarray repräsentiert ein Java-Array • jobjectArray Array von Objekten • jbooleanArray Array mit boolean-Werten • jbyteArray Array mit byte-Werten • jcharArray Array mit char-Werten • jshortArray Array mit short-Werten • jintArray Array mit int-Werten • jlongArray Array mit long-Werten • jfloatArray Array mit float-Werten • jdoubleArray Array mit double-Werten • Throwable jthrowable repräsentiert Java-Exceptions EDV 1 - Java Native Interface
Java Arrays sind keine primitiven Datentypen. Hier gibt es besondere Funktionen für Arrays. • jarray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement); • jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index); • void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value); Anstelle vonobjectwird der Datentyp angegeben. Nun ein konkretes Beispiel mit einem vorausgesetzten Quicksortalgorithmus. EDV 1 - Java Native Interface
Java-File mit nativer-Methode schreiben: class JavaKlasse { // native Methode public native double[] Jquicksort( double []); // Einmaliger Aufruf der Bibliothek (dll) static { System.loadLibrary("QuickSort"); } // main-Methode public static void main( String args[]) { // Initialisierung vom Vektor double [] vector; ... // Aufruf der nativen Methode vector = new JavaKlasse.Jquicksort(vector); ... // Anzeigen vector } } EDV 1 - Java Native Interface
Generiertes Header-File mit "javah -jni JavaKlasse": /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class JavaKlasse */ #ifndef _Included_JavaKlasse#define _Included_JavaKlasse #ifdef __cplusplusextern "C" {#endif /* * Class: JavaKlasse * Method: Jquicksort * Signature: ([D)[D */ JNIEXPORT jdoubleArray JNICALLJava_JavaKlasse_Jquicksort (JNIEnv *, jobject, jdoubleArray); #ifdef __cplusplus} #endif #endif Hier erkennt man die Signatur der Nativen-Methode (Blau dargestellt). In dem folgenden C-File wird diese Methode nun implementiert. EDV 1 - Java Native Interface
#include <stdio.h> #include <jni.h> #include "JavaKlasse.h" JNIEXPORT jdoubleArray JNICALL Java_JavaKlasse_Jquicksort (JNIEnv * env, jobject jobj, jdoubleArray jarr){ // Der Vektor muß mit seiner Länge übernommen werden. jsize l = (*env)->GetArrayLength(env, jarr); jdouble *vector = (*env)->GetDoubleArrayElements(env, jarr, 0); /* Aufruf der Methode QuickSort in der Bibliothek QuickSort.dll dieses C-File muß in der gleichen Bilbiothek zur verfügung stehen. */ QuickSort(vector, l) // Speicher freigeben und rückkopieren des Array. (*env)->ReleaseDoubleArrayElements(env, jarr, vector, 0); return jarr; } EDV 1 - Java Native Interface
Hier ein paar Anmerkungen: In Java ist die Längeninformation der Arrays im Objekt „Array“ mit inbegriffen. In C ist dies nicht der Fall. So wird vom JNI eine Methode bereitgestellt, die die Länge aus liest. (*env)->GetArrayLength(env, myarray);JNI stellt für die Länge auch ein besondere Variable zur Verfügung: „jsize“ In C wird ein Array mit Pointer (Zeiger) realisiert. Deswegen wird wird das Feld auf ein Pointer gelegt.jdouble *c_feld = (*env)->GetDoubleArrayElements(env, myarray, 0); Um den Speicher der hier in c_feld belegt wurde wieder frei zu machen, wird die Funktion ReleaseDoubleArrayElements()verwendet. Zusätzlich kopiert sie das entsprechende (hier) Array zurück. EDV 1 - Java Native Interface
Quellen: • http://java.sun.com/docs/books/tutorial/ • http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/jni.html • http://www.informatik.fh-muenchen.de/~schieder/seminar-java-ss98/jni/JNI.html • http://www.informatik.uni-osnabrueck.de/bernd/Artikel/jni_1.html • http://www.informatik.uni-osnabrueck.de/bernd/Artikel/jni_2.html • http://www.tu-chemnitz.de/urz/java/cjug/3/main.html • http://fred.ukbf.fu-berlin.de/~hangloos/c_in_java/main.html EDV 1 - Java Native Interface