jni.h

Werbung
Java
mit eingebundenen
(native) C-Programme
Vortrag: Rolf Heitzenröder
am 29.6.2000
EDV 1 - Java Native Interface
1
Warum JNI?
EDV 1 - Java Native Interface
2
Java bietet eine Vielzahl von Möglichkeiten der Programmierung.
Angefangen von graphischen Verschönern bis hin zur Netzwerkund 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
3
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.
Wie wird nun JNI angewendet?
EDV 1 - Java Native Interface
4
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
5
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!
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.
EDV 1 - Java Native Interface
6
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();
}
Hier das "alt" bekannte Hello-World-Programm (Java Seite):
class HelloWorld {
public native void displayHelloWorld();
EDV 1 - Java Native Interface
7
static { System.laodLibrary("hello"); }
public static void main(String[] args) {
new HelloWorld().displayHelloWorld();
}
Dieses Java Programm wird normal compilert. Mit der erzeugten ClassDatei 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
8
/* 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 ...
mit den folgenden Zeilen:
EDV 1 - Java Native Interface
/*
* 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 .
9
"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.
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
EDV 1 - Java Native Interface
10
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.
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
11
Übersicht der Datentypen:
In C haben die primitiven Datentypen den gleichen Namen, nur mit einem j vorangestellt.
EDV 1 - Java Native Interface
12
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
13
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
Java Arrays sind keine primitiven Datentypen.
Hier gibt es besondere Funktionen für Arrays.
EDV 1 - Java Native Interface
14
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 von object wird der Datentyp angegeben.
Nun ein konkretes Beispiel mit einem vorausgesetzten
Quicksortalgorithmus.
EDV 1 - Java Native Interface
15
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
}
}
Generiertes Header-File mit "javah -jni JavaKlasse":
EDV 1 - Java Native Interface
/* 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 JNICALL Java_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.
16
#include <stdio.h>
#include <jni.h>
#include "JavaKlasse.h"
JNIEXPORT jdoubleArray JNICALL Java_JavaKlasse_Jquicksort
(JNIEnv * env, jobject jobj, jdoubleArray jarr){
EDV 1 - Java Native Interface
// 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;
}
17
EDV 1 - Java Native Interface
18
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.
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
EDV 1 - Java Native Interface
19
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
Herunterladen