Native Java-Schnittstelle - Java Native Interface
In Software - Design , das Java Native Interface ( JNI ist) eine Fremdfunktionsschnittstelle Programmierung Framework , das ermöglicht Java Ausführen von Code in einer virtuellen Java - Maschine von nativen Anwendungen (Programme spezifisch für eine Hardware und (JVM) zu nennen und wird genannt Betriebssystem - Plattform) und Bibliotheken, die in anderen Sprachen wie C , C++ und Assembly geschrieben sind .
Ziele
JNI ermöglicht Programmierer native Methoden zu schreiben , um Griff Situationen , wenn eine Anwendung nicht vollständig in der Programmiersprache Java geschrieben werden kann, zum Beispiel , wenn die Standard - Java - Klassenbibliothek nicht die plattformspezifische Funktionen oder Programmbibliothek unterstützt. Es wird auch verwendet, um eine vorhandene Anwendung (in einer anderen Programmiersprache geschrieben) so zu ändern, dass sie für Java-Anwendungen zugänglich ist. Viele der Standardbibliotheksklassen hängen von JNI ab, um dem Entwickler und dem Benutzer Funktionalität bereitzustellen, zB Datei-I/O und Sound-Fähigkeiten. Die Aufnahme von performance- und plattformsensitiven API-Implementierungen in die Standardbibliothek ermöglicht allen Java-Anwendungen den sicheren und plattformunabhängigen Zugriff auf diese Funktionalität.
Das JNI-Framework ermöglicht es einer nativen Methode, Java- Objekte auf dieselbe Weise zu verwenden, wie Java-Code diese Objekte verwendet. Eine native Methode kann Java-Objekte erstellen und diese Objekte dann untersuchen und verwenden, um ihre Aufgaben auszuführen. Eine native Methode kann auch Objekte untersuchen und verwenden, die von Java-Anwendungscode erstellt wurden.
Nur Anwendungen und signierte Applets können JNI aufrufen.
Eine Anwendung, die auf JNI basiert, verliert die Plattformportabilität, die Java bietet (eine teilweise Problemumgehung besteht darin, eine separate Implementierung von JNI-Code für jede Plattform zu schreiben und Java das Betriebssystem erkennen und das richtige zur Laufzeit laden zu lassen).
Es kann nicht nur nativer Code mit Java kommunizieren, sondern auch auf Java zurückgreifen Canvas
, was mit dem Java AWT Native Interface möglich ist . Der Prozess ist fast der gleiche, mit nur wenigen Änderungen. Das Java AWT Native Interface ist erst seit J2SE 1.3 verfügbar .
JNI ermöglicht auch den direkten Zugriff auf Assemblercode , ohne eine C- Bridge zu durchlaufen . Der Zugriff auf Java-Anwendungen aus der Assembly ist auf die gleiche Weise möglich.
Entwurf
Im JNI-Framework werden native Funktionen in separaten .c- oder .cpp-Dateien implementiert. (C++ bietet eine etwas einfachere Schnittstelle mit JNI.) Wenn die JVM die Funktion aufruft, übergibt sie einen JNIEnv
Zeiger, einen jobject
Zeiger und alle von der Java-Methode deklarierten Java-Argumente. Folgendes wandelt beispielsweise einen Java-String in einen nativen String um:
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
const char *nativeString = env->GetStringUTFChars(javaString, 0);
//Do something with the nativeString
env->ReleaseStringUTFChars(javaString, nativeString);
}
Der env
Zeiger ist eine Struktur, die die Schnittstelle zur JVM enthält. Es enthält alle Funktionen, die für die Interaktion mit der JVM und für die Arbeit mit Java-Objekten erforderlich sind. JNI-Beispielfunktionen sind das Konvertieren von nativen Arrays in/aus Java-Arrays, das Konvertieren nativer Strings in/aus Java-Strings, das Instanziieren von Objekten, das Auslösen von Ausnahmen usw. Grundsätzlich kann alles, was Java-Code tun kann, mit verwendet werden JNIEnv
, wenn auch mit erheblich geringerem Aufwand.
Das Argument obj
ist eine Referenz auf das Java-Objekt, in dem diese native Methode deklariert wurde.
Native Datentypen können auf/von Java-Datentypen abgebildet werden. Bei zusammengesetzten Typen wie Objekten, Arrays und Strings muss der native Code die Daten explizit konvertieren, indem er Methoden in der JNIEnv
.
Ein JNI-Umgebungszeiger ( JNIEnv* ) wird als Argument für jede einer Java-Methode zugeordnete native Funktion übergeben, die eine Interaktion mit der JNI-Umgebung innerhalb der nativen Methode ermöglicht. Dieser JNI-Schnittstellenzeiger kann gespeichert werden, bleibt jedoch nur im aktuellen Thread gültig. Andere Threads müssen zuerst AttachCurrentThread() aufrufen , um sich an die VM anzuhängen und einen JNI-Schnittstellenzeiger zu erhalten. Nach dem Anhängen funktioniert ein nativer Thread wie ein normaler Java-Thread, der innerhalb einer nativen Methode ausgeführt wird. Der native Thread bleibt an die VM angehängt, bis er DetachCurrentThread() aufruft , um sich selbst zu trennen .
Das JNI-Framework bietet keine automatische Garbage Collection für Nicht-JVM-Speicherressourcen, die von Code zugewiesen werden, der auf der nativen Seite ausgeführt wird. Folglich übernimmt nativer Seitencode (wie Assemblersprache) die Verantwortung für die explizite Freigabe solcher Speicherressourcen, die der native Code erwirbt.
Wenn sich der native Code auf Linux- und Solaris-Plattformen als Signalhandler registriert, könnte er Signale abfangen, die für die JVM bestimmt sind. Eine Verantwortungskette kann verwendet werden, damit nativer Code besser mit der JVM zusammenarbeiten kann. Auf Windows-Plattformen kann Structured Exception Handling (SEH) verwendet werden, um nativen Code in SEH-Try/Catch-Blöcke einzuschließen, um von der Maschine (CPU/FPU) generierte Software-Interrupts (wie NULL-Zeigerzugriffsverletzungen und Division-durch-Null-Operationen) zu erfassen ) und diese Situationen zu behandeln, bevor der Interrupt zurück in die JVM (dh Java-Seitencode) propagiert wird, was aller Wahrscheinlichkeit nach zu einer unbehandelten Ausnahme führt.
Die für die Funktionen NewStringUTF, GetStringUTFLength, GetStringUTFChars, ReleaseStringUTFChars und GetStringUTFRegion verwendete Codierung ist "modifiziertes UTF-8", was nicht für alle Eingaben gültiges UTF-8 ist, sondern tatsächlich eine andere Codierung. Das Nullzeichen (U+0000) und Codepunkte, die sich nicht auf der Basic Multilingual Plane befinden (größer oder gleich U+10000, dh diejenigen, die in UTF-16 als Ersatzpaare dargestellt werden ) werden in modifiziertem UTF-8 anders codiert. Viele Programme verwenden diese Funktionen tatsächlich falsch und behandeln die zurückgegebenen oder an die Funktionen übergebenen UTF-8-Strings als Standard-UTF-8-Strings anstelle von modifizierten UTF-8-Strings. Programme sollten die Funktionen NewString, GetStringLength, GetStringChars, ReleaseStringChars, GetStringRegion, GetStringCritical und ReleaseStringCritical verwenden, die die UTF-16LE-Codierung auf Little-Endian-Architekturen und UTF-16BE auf Big-Endian-Architekturen verwenden, und dann UTF-16 zu UTF- 8 Konvertierungsroutine.
Zuordnungstypen
Die folgende Tabelle zeigt die Zuordnung von Typen zwischen Java (JNI) und nativem Code.
C-Typ | Java-Sprachtyp | Beschreibung | Unterschrift eingeben |
---|---|---|---|
unsigniertes Zeichen uint8_t |
jboolean | vorzeichenlose 8 Bit | Z |
signiertes Zeichen int8_t |
jbyte | vorzeichenbehaftet 8 Bit | B |
unsigned short uint16_t |
jchar | vorzeichenlose 16 Bit | C |
kurz int16_t |
jkurz | vorzeichenbehaftet 16 Bit | S |
int int32_t |
jint | vorzeichenbehaftet 32 Bit | ich |
lang lang |
jlong | vorzeichenbehaftet 64 Bit | J |
schweben | jfloat | 32 Bit | F |
doppelt | jdouble | 64 Bit | D |
Leere | V |
Außerdem "L fully-qualified-class ;"
würde die Signatur die durch diesen Namen eindeutig spezifizierte Klasse bedeuten; zB "Ljava/lang/String;"
bezieht sich die Signatur auf die Klasse java.lang.String
. Außerdem wird durch das Präfixieren [
der Signatur das Array von diesem Typ; zum Beispiel [I
bedeutet den int - Array - Typ. Schließlich verwendet eine void
Signatur den V
Code.
Diese Typen sind austauschbar. Sie können dort verwenden, jint
wo Sie normalerweise ein verwenden int
, und umgekehrt, ohne dass eine Typumwandlung erforderlich ist. Die Zuordnung zwischen Java-Strings und -Arrays zu nativen Strings und Arrays ist jedoch anders. Wenn a verwendet jstring
wird, wo a char *
wäre, könnte der Code die JVM zum Absturz bringen.
Leistung
JNI erleidet unter Umständen erheblichen Overhead und Performance-Einbußen:
- Funktionsaufrufe von JNI-Methoden sind teuer, insbesondere wenn eine Methode wiederholt aufgerufen wird.
- Native Methoden werden nicht von der JVM inline eingebunden, und die Methode kann auch nicht JIT-kompiliert werden , da die Methode bereits kompiliert ist.
- Ein Java-Array kann für den Zugriff im nativen Code kopiert und später zurückkopiert werden. Die Kosten können in der Größe des Arrays linear sein.
- Wenn der Methode ein Objekt übergeben wird oder ein Rückruf erforderlich ist, führt die native Methode wahrscheinlich ihre eigenen Aufrufe an die JVM durch. Der Zugriff auf Java-Felder, -Methoden und -Typen aus dem nativen Code erfordert etwas Ähnliches wie Reflection . Signaturen werden in Strings angegeben und von der JVM abgefragt. Dies ist sowohl langsam als auch fehleranfällig.
- Java Strings sind Objekte, haben eine Länge und sind codiert. Für den Zugriff auf oder das Erstellen einer Zeichenfolge ist möglicherweise eine O(n)-Kopie erforderlich.
Alternativen
Microsofts proprietäre Implementierung einer Java Virtual Machine ( Visual J++ ) hatte einen ähnlichen Mechanismus zum Aufrufen von nativem Code aus Java, genannt Raw Native Interface ( RNI ). Darüber hinaus gab es eine einfache Möglichkeit, vorhandenen nativen Code aufzurufen, der selbst Java nicht kannte, wie (aber nicht beschränkt auf) die Windows-API namens J/Direct . Nach dem Rechtsstreit zwischen Sun und Microsoft zu dieser Implementierung wird Visual J++ jedoch nicht mehr verwaltet.
RNI war weniger umständlich zu verwenden als JNI, da keine Buchhaltung mit einem Java-Umgebungszeiger erforderlich war. Stattdessen könnte auf alle Java-Objekte direkt zugegriffen werden. Um dies zu erleichtern, wurde ein Tool verwendet, das Header-Dateien aus Java-Klassen generierte. In ähnlicher Weise war J/Direct einfacher zu verwenden als die Verwendung der erforderlichen nativen Zwischenbibliothek und JNI.
Java Native Access (JNA) ist eine von der Community entwickelte Bibliothek, die Java-Programmen einen einfachen Zugriff auf native gemeinsam genutzte Bibliotheken ermöglicht, ohne JNI zu verwenden.
Siehe auch
Verweise
Literaturverzeichnis
- Gordon, Rob (März 1998). Essential Jni: Java Native Interface (1. Aufl.). Lehrlingssaal . P. 498. ISBN 0-13-679895-0.
- Liang, Sheng (20. Juni 1999). Java(TM) Native Interface: Programmierhandbuch und Spezifikation (1. Aufl.). Lehrlingssaal . P. 320. ISBN 0-201-32577-2.