Ah, natürlich hatte ich die JNI-Aspekte nicht berücksichtigt ... Vielen Dank an alle!
Hybris
Antworten:
114
Die anderen Antworten sind technisch korrekt, aber für jemanden ohne JNI-Erfahrung nicht sehr nützlich. :-)
Damit die JVM Ihre nativen Funktionen finden kann, müssen sie normalerweise auf eine bestimmte Weise benannt werden. zB wird für java.lang.Object.registerNativesdie entsprechende C-Funktion benannt Java_java_lang_Object_registerNatives. Mit registerNatives(oder besser gesagt mit der JNI-Funktion RegisterNatives) können Sie Ihre C-Funktionen beliebig benennen.
(Beachten Sie, dass dies Object.getClassnicht in der Liste enthalten ist. Es wird weiterhin mit dem "Standard" -Namen von aufgerufen Java_java_lang_Object_getClass.) Für die aufgelisteten Funktionen sind die zugehörigen C-Funktionen wie in dieser Tabelle aufgeführt. Dies ist einfacher als das Schreiben einer Reihe von Weiterleitungsfunktionen.
Das Registrieren nativer Funktionen ist auch nützlich, wenn Sie Java in Ihr C-Programm einbetten und eine Verknüpfung zu Funktionen in der Anwendung selbst herstellen möchten (im Gegensatz zu einer gemeinsam genutzten Bibliothek) oder wenn die verwendeten Funktionen nicht anderweitig "exportiert" werden, da diese nicht "exportiert" werden würde normalerweise nicht vom Standard-Methodensuchmechanismus gefunden werden. Das Registrieren nativer Funktionen kann auch verwendet werden, um eine native Methode an eine andere C-Funktion "neu zu binden" (nützlich, wenn Ihr Programm beispielsweise das dynamische Laden und Entladen von Modulen unterstützt).
Ich ermutige alle, das JNI-Buch zu lesen , in dem es um dieses und vieles mehr geht. :-)
Sie haben einen vollständig dekorierten JNI-Funktionsnamen geschrieben, was ihn verwirrend macht: Java_java_lang_Object_registerNativesWird von VM automatisch aufgerufen, oder c / c ++ - Code muss diese Funktion aufrufen, und es besteht keine Notwendigkeit für all das Java-Gobblygook
Pavel P
@Pavel Standardmäßig wird eine native Methode methodNamein der Klasse fully.qualified.ClassNameunter dem C-Namen gesucht Java_fully_qualified_ClassName_methodName(den Ihr C- seitiger Code exportieren muss). Sie können die Methode aufrufen JNIEnv, RegisterNativesum diese Verknüpfung zu überschreiben. Mit anderen Worten, wenn Sie nicht RegisterNativeszuerst verwenden, ist "all das Java-Gobblygook" erforderlich.
Chris Jester-Young
Ah, ok, also durch Exportieren von nur 1 Funktion Java_java_lang_Object_registerNativeskann ich tatsächlich alle meine JNI-Sachen verknüpfen , indem ich den Wert von überprüfe cls. Ich habe den Teil verpasst, dass registerNatives tatsächlich Teil von Java selbst ist. Also ... wenn eine Klasse verwendet werden soll, wie sieht die Reihenfolge der Aktionen aus, mit denen JVM Eingeborene verknüpft? Es scheint, dass JVM, wenn die Eingeborenen noch nicht registriert sind (aus c / c ++), nach all diesen exportierten Namen sucht. Wenn sie nicht vorhanden sind, versucht sie, Object.registerNatives zu verwenden (oder umgekehrt?). Der jni book Link ist übrigens tot.
Pavel P
Wenn Sie nicht aufgerufen RegisterNativeshaben und die exportierten Namen nicht verfügbar sind, wird beim Versuch, die Methode aufzurufen, ein Laufzeitfehler angezeigt. Object.registerNativesist eine interne Methode der OpenJDK-Implementierung von java.lang.Object, die vom Klasseninitialisierer aufgerufen wird. Ihr einziger Zweck besteht darin, die nativen Methoden zu registrieren, die nur diese betreffen java.lang.Object. Wenn Sie Ihre eigene native Bibliothek schreiben, liegt es an Ihnen, die nativen Methoden Ihrer Bibliothek selbst zu registrieren (falls Sie dies wünschen).
Chris Jester-Young
11
Was etwas verwirrend sein kann, ist, dass der java.lang.Object.registerNativesin einer vorherigen Antwort gezeigte Code nur ein Beispiel für die Registrierung nativer Funktionen ist. Dies ist der Code, der (in der Implementierung von OpenJDK) native Funktionen für die Klasse Object registriert. Um native Funktionen für Ihre eigene Klasse zu registrieren, müssen Sie die JNI-Funktion RegisterNativesaus dem nativen Code in Ihrer eigenen Bibliothek aufrufen . Das klingt vielleicht etwas kreisförmig, aber es gibt verschiedene Möglichkeiten, die Schleife zu durchbrechen.
Folgen Sie dem Beispiel dieser Implementierung der Klasse Object:
ein. Deklarieren Sie in Ihrer Java-Klasse eine native Methode (vorzugsweise statisch) mit dem Namen registerNatives(oder einen anderen Namen. Es spielt keine Rolle).
b. Definieren Sie in Ihrem nativen Code eine Funktion mit dem Namen Java_<your fully qualified class name>_registerNatives, die einen Aufruf der JNI-Funktion enthält RegisterNatives.
c. Stellen Sie sicher, dass in Ihrem Java-Code Ihre Java- registerNativesMethode aufgerufen wird, bevor Sie andere native Methoden aufrufen.
ODER
Verwenden JNI_OnLoad
ein. Definieren Sie in Ihrer nativen Bibliothek eine Funktion jint JNI_OnLoad(JavaVM *vm, void *reserved). Rufen Sie im Hauptteil dieser Funktion die JNI-Funktion auf RegisterNatives.
b. Die Java-VM sucht und ruft automatisch auf, JNI_OnLoadwenn Ihre native Bibliothek von geladen wird System.loadLibrary, die Sie bereits aufrufen sollten, wahrscheinlich in einem statischen Initialisierer für Ihre Klasse. (Sie erhalten den erforderlichen envZeiger, indem Sie die GetEnvFunktion in der Tabelle aufrufen, auf die der vmZeiger zeigt.)
Antworten:
Die anderen Antworten sind technisch korrekt, aber für jemanden ohne JNI-Erfahrung nicht sehr nützlich. :-)
Damit die JVM Ihre nativen Funktionen finden kann, müssen sie normalerweise auf eine bestimmte Weise benannt werden. zB wird für
java.lang.Object.registerNatives
die entsprechende C-Funktion benanntJava_java_lang_Object_registerNatives
. MitregisterNatives
(oder besser gesagt mit der JNI-FunktionRegisterNatives
) können Sie Ihre C-Funktionen beliebig benennen.Hier ist der zugehörige C-Code (aus OpenJDK 6):
static JNINativeMethod methods[] = { {"hashCode", "()I", (void *)&JVM_IHashCode}, {"wait", "(J)V", (void *)&JVM_MonitorWait}, {"notify", "()V", (void *)&JVM_MonitorNotify}, {"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll}, {"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone}, }; JNIEXPORT void JNICALL Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); }
(Beachten Sie, dass dies
Object.getClass
nicht in der Liste enthalten ist. Es wird weiterhin mit dem "Standard" -Namen von aufgerufenJava_java_lang_Object_getClass
.) Für die aufgelisteten Funktionen sind die zugehörigen C-Funktionen wie in dieser Tabelle aufgeführt. Dies ist einfacher als das Schreiben einer Reihe von Weiterleitungsfunktionen.Das Registrieren nativer Funktionen ist auch nützlich, wenn Sie Java in Ihr C-Programm einbetten und eine Verknüpfung zu Funktionen in der Anwendung selbst herstellen möchten (im Gegensatz zu einer gemeinsam genutzten Bibliothek) oder wenn die verwendeten Funktionen nicht anderweitig "exportiert" werden, da diese nicht "exportiert" werden würde normalerweise nicht vom Standard-Methodensuchmechanismus gefunden werden. Das Registrieren nativer Funktionen kann auch verwendet werden, um eine native Methode an eine andere C-Funktion "neu zu binden" (nützlich, wenn Ihr Programm beispielsweise das dynamische Laden und Entladen von Modulen unterstützt).
Ich ermutige alle, das JNI-Buch zu lesen , in dem es um dieses und vieles mehr geht. :-)
quelle
Java_java_lang_Object_registerNatives
Wird von VM automatisch aufgerufen, oder c / c ++ - Code muss diese Funktion aufrufen, und es besteht keine Notwendigkeit für all das Java-GobblygookmethodName
in der Klassefully.qualified.ClassName
unter dem C-Namen gesuchtJava_fully_qualified_ClassName_methodName
(den Ihr C- seitiger Code exportieren muss). Sie können die Methode aufrufenJNIEnv
,RegisterNatives
um diese Verknüpfung zu überschreiben. Mit anderen Worten, wenn Sie nichtRegisterNatives
zuerst verwenden, ist "all das Java-Gobblygook" erforderlich.Java_java_lang_Object_registerNatives
kann ich tatsächlich alle meine JNI-Sachen verknüpfen , indem ich den Wert von überprüfecls
. Ich habe den Teil verpasst, dass registerNatives tatsächlich Teil von Java selbst ist. Also ... wenn eine Klasse verwendet werden soll, wie sieht die Reihenfolge der Aktionen aus, mit denen JVM Eingeborene verknüpft? Es scheint, dass JVM, wenn die Eingeborenen noch nicht registriert sind (aus c / c ++), nach all diesen exportierten Namen sucht. Wenn sie nicht vorhanden sind, versucht sie, Object.registerNatives zu verwenden (oder umgekehrt?). Der jni book Link ist übrigens tot.RegisterNatives
haben und die exportierten Namen nicht verfügbar sind, wird beim Versuch, die Methode aufzurufen, ein Laufzeitfehler angezeigt.Object.registerNatives
ist eine interne Methode der OpenJDK-Implementierung vonjava.lang.Object
, die vom Klasseninitialisierer aufgerufen wird. Ihr einziger Zweck besteht darin, die nativen Methoden zu registrieren, die nur diese betreffenjava.lang.Object
. Wenn Sie Ihre eigene native Bibliothek schreiben, liegt es an Ihnen, die nativen Methoden Ihrer Bibliothek selbst zu registrieren (falls Sie dies wünschen).Was etwas verwirrend sein kann, ist, dass der
java.lang.Object.registerNatives
in einer vorherigen Antwort gezeigte Code nur ein Beispiel für die Registrierung nativer Funktionen ist. Dies ist der Code, der (in der Implementierung von OpenJDK) native Funktionen für die Klasse Object registriert. Um native Funktionen für Ihre eigene Klasse zu registrieren, müssen Sie die JNI-FunktionRegisterNatives
aus dem nativen Code in Ihrer eigenen Bibliothek aufrufen . Das klingt vielleicht etwas kreisförmig, aber es gibt verschiedene Möglichkeiten, die Schleife zu durchbrechen.Folgen Sie dem Beispiel dieser Implementierung der Klasse Object:
ein. Deklarieren Sie in Ihrer Java-Klasse eine native Methode (vorzugsweise statisch) mit dem Namen
registerNatives
(oder einen anderen Namen. Es spielt keine Rolle).b. Definieren Sie in Ihrem nativen Code eine Funktion mit dem Namen
Java_<your fully qualified class name>_registerNatives
, die einen Aufruf der JNI-Funktion enthältRegisterNatives
.c. Stellen Sie sicher, dass in Ihrem Java-Code Ihre Java-
registerNatives
Methode aufgerufen wird, bevor Sie andere native Methoden aufrufen.ODER
Verwenden
JNI_OnLoad
ein. Definieren Sie in Ihrer nativen Bibliothek eine Funktion
jint JNI_OnLoad(JavaVM *vm, void *reserved)
. Rufen Sie im Hauptteil dieser Funktion die JNI-Funktion aufRegisterNatives
.b. Die Java-VM sucht und ruft automatisch auf,
JNI_OnLoad
wenn Ihre native Bibliothek von geladen wirdSystem.loadLibrary
, die Sie bereits aufrufen sollten, wahrscheinlich in einem statischen Initialisierer für Ihre Klasse. (Sie erhalten den erforderlichenenv
Zeiger, indem Sie dieGetEnv
Funktion in der Tabelle aufrufen, auf die dervm
Zeiger zeigt.)quelle