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 JNIEnvZeiger, einen jobjectZeiger 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 envZeiger 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 objist 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
int64_t

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 [Ibedeutet den int - Array - Typ. Schließlich verwendet eine voidSignatur den VCode.

Diese Typen sind austauschbar. Sie können dort verwenden, jintwo 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 jstringwird, 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

Externe Links