Beim Spielen dieses Puzzles (es ist ein Java-Keyword-Quizspiel) bin ich auf das nativeKeyword gestoßen.
Wofür wird das native Schlüsselwort in Java verwendet?
Beim Spielen dieses Puzzles (es ist ein Java-Keyword-Quizspiel) bin ich auf das nativeKeyword gestoßen.
Wofür wird das native Schlüsselwort in Java verwendet?
Antworten:
Das nativeSchlüsselwort wird auf eine Methode angewendet, um anzugeben, dass die Methode mithilfe von JNI (Java Native Interface) in nativem Code implementiert ist.
Minimal lauffähiges Beispiel
Main.java
public class Main {
public native int square(int i);
public static void main(String[] args) {
System.loadLibrary("Main");
System.out.println(new Main().square(2));
}
}
Haupt c
#include <jni.h>
#include "Main.h"
JNIEXPORT jint JNICALL Java_Main_square(
JNIEnv *env, jobject obj, jint i) {
return i * i;
}
Kompilieren und ausführen:
sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main
Ausgabe:
4
Getestet unter Ubuntu 14.04 AMD64. Funktionierte auch mit Oracle JDK 1.8.0_45.
Beispiel auf GitHub, mit dem Sie spielen können.
Unterstriche in Java-Paket- / Dateinamen müssen _1im C-Funktionsnamen maskiert werden, wie unter: Aufrufen von JNI-Funktionen im Android-Paketnamen mit Unterstrich
Deutung
native erlaubt dir zu:
Dies könnte verwendet werden, um:
mit dem Kompromiss einer geringeren Portabilität.
Sie können Java auch von C aus aufrufen, müssen jedoch zuerst eine JVM in C erstellen: Wie rufe Java-Funktionen von C ++ auf?
Analoge native Erweiterungs-APIs sind aus den gleichen Gründen auch in vielen anderen "VM-Sprachen" vorhanden, z. B. Python , Node.js , Ruby .
Android NDK
Das Konzept ist in diesem Zusammenhang genau das gleiche, außer dass Sie Android Boilerplate verwenden müssen, um es einzurichten.
Das offizielle NDK-Repository enthält "kanonische" Beispiele wie die Hallo-JNI-App:
In unzipeinem .apkmit NDK auf Android O können Sie den vorkompilierten .soCode sehen, der dem nativen Code unter entspricht lib/arm64-v8a/libnative-lib.so.
TODO bestätigen: Außerdem handelt file /data/app/com.android.appname-*/oat/arm64/base.odexes sich um eine gemeinsam genutzte Bibliothek, bei der es sich meiner Meinung nach um die vorkompilierte AOT-.dex handelt, die den Java-Dateien in ART entspricht. Siehe auch: Was sind ODEX-Dateien in Android? Vielleicht wird Java tatsächlich auch über a ausgeführtnative Schnittstelle ausgeführt?
Beispiel im OpenJDK 8
Lassen Sie uns finden, wo Object#clone in jdk8u60-b27 definiert ist.
Wir werden daraus schließen, dass es mit a implementiert wird native Aufruf umgesetzt wird.
Zuerst finden wir:
find . -name Object.java
was uns zu jdk / src / share / classes / java / lang / Object.java # l212 führt :
protected native Object clone() throws CloneNotSupportedException;
Jetzt kommt der schwierige Teil, herauszufinden, wo sich der Klon inmitten aller Indirektion befindet. Die Frage, die mir geholfen hat, war:
find . -iname object.c
Hier werden entweder C- oder C ++ - Dateien gefunden, die die nativen Methoden von Object implementieren könnten. Es führt uns zu jdk / share / native / java / lang / Object.c # l47 :
static JNINativeMethod methods[] = {
...
{"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]));
}
was uns zum JVM_CloneSymbol führt:
grep -R JVM_Clone
was uns zu hotspot / src / share / vm / prims / jvm.cpp # l580 führt :
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
Nachdem wir eine Reihe von Makros erweitert haben, kommen wir zu dem Schluss, dass dies der Definitionspunkt ist.
static nativeJava-Methode ist der zweite Parameter der C ++ - Funktion vom Typ jclassund nicht vom Typ jobject.
Es markiert eine Methode, die in anderen Sprachen implementiert wird, nicht in Java. Es funktioniert zusammen mit JNI (Java Native Interface).
In der Vergangenheit wurden native Methoden verwendet, um leistungskritische Abschnitte zu schreiben. Da Java jedoch immer schneller wird, ist dies jetzt weniger verbreitet. Native Methoden werden derzeit benötigt, wenn
Sie müssen eine Bibliothek aus Java aufrufen, die in einer anderen Sprache geschrieben ist.
Sie müssen auf System- oder Hardwareressourcen zugreifen, die nur von der anderen Sprache aus erreichbar sind (normalerweise C). Tatsächlich können viele Systemfunktionen, die mit einem realen Computer interagieren (z. B. Festplatten- und Netzwerk-E / A), dies nur, weil sie nativen Code aufrufen.
Siehe auch Java Native Interface-Spezifikation
currentTimeMillissind Teil des JDK und werden mit Anmerkungen versehen, nativeda sich die Implementierung im JDK-Quellcode selbst befindet. Es ist sehr unwahrscheinlich, dass die Implementierung Assemblersprache verwendet. Es ruft wahrscheinlich eine API-Methode des Betriebssystems auf, auf dem die JVM ausgeführt wird. Unter Windows kann beispielsweise eine DLL-Methode GetSystemTimein kernel32.dll aufgerufen werden . Auf einem anderen Betriebssystem wird es eine andere Implementierung haben. Wenn Sie jedoch nativefür eine Methode verwenden, die Sie schreiben (im Gegensatz zu einer JDK-Methode), müssen Sie die Implementierung mithilfe von JNI bereitstellen.
currentTimeMillisist in als nativ markiert java.lang.System, verwendet also JNI, stimmt das nicht?
Direkt aus der Java-Sprachspezifikation :
Eine Methode,
nativedie in plattformabhängigem Code implementiert ist und normalerweise in einer anderen Programmiersprache wie C, C ++, FORTRAN oder Assemblersprache geschrieben ist. Der Hauptteil einernativeMethode wird nur als Semikolon angegeben, was darauf hinweist, dass die Implementierung anstelle eines Blocks weggelassen wird.
Funktionen, die nativen Code implementieren, werden als nativ deklariert.
Das Java Native Interface (JNI) ist ein Programmierframework, mit dem Java-Code, der in einer Java Virtual Machine (JVM) ausgeführt wird, native Anwendungen (Programme, die für eine Hardware- und Betriebssystemplattform spezifisch sind) und Bibliotheken, in die geschrieben wurde, aufrufen und von diesen aufgerufen werden kann andere Sprachen wie C, C ++ und Assembly.
native ist ein Schlüsselwort in Java, das verwendet wird, um nicht implementierte Strukturen (Methoden) wie abstrakt zu machen, aber es wäre plattformabhängig wie nativer Code und würde vom nativen Stapel ausgeführt, nicht vom Java-Stapel.
Die Java- nativeMethode bietet einen Mechanismus für Java-Code zum Aufrufen von nativem OS-Code, entweder aus funktionalen oder aus Leistungsgründen.
Beispiel:
606 public native int availableProcessors();
617 public native long freeMemory();
630 public native long totalMemory();
641 public native long maxMemory();
664 public native void gc();
In der entsprechenden Runtime.classDatei in OpenJDK, die sich in befindet JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, sind diese Methoden enthalten und mit ACC_NATIVE( 0x0100) gekennzeichnet. Diese Methoden enthalten kein Code-Attribut . Dies bedeutet, dass diese Methode keine tatsächliche Codierungslogik in der Runtime.classDatei enthält:
availableProcessors: als nativ und ohne Code-Attribut markiertfreeMemory: als nativ und ohne Code-Attribut markierttotalMemory: als nativ und ohne Code-Attribut markiertmaxMemory: als nativ und ohne Code-Attribut markiertgc: als nativ und ohne Code-Attribut markiertDie eigentliche Codierungslogik befindet sich in der entsprechenden Runtime.c- Datei:
42 #include "java_lang_Runtime.h"
43
44 JNIEXPORT jlong JNICALL
45 Java_java_lang_Runtime_freeMemory(JNIEnv *env, jobject this)
46 {
47 return JVM_FreeMemory();
48 }
49
50 JNIEXPORT jlong JNICALL
51 Java_java_lang_Runtime_totalMemory(JNIEnv *env, jobject this)
52 {
53 return JVM_TotalMemory();
54 }
55
56 JNIEXPORT jlong JNICALL
57 Java_java_lang_Runtime_maxMemory(JNIEnv *env, jobject this)
58 {
59 return JVM_MaxMemory();
60 }
61
62 JNIEXPORT void JNICALL
63 Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
64 {
65 JVM_GC();
66 }
67
68 JNIEXPORT jint JNICALL
69 Java_java_lang_Runtime_availableProcessors(JNIEnv *env, jobject this)
70 {
71 return JVM_ActiveProcessorCount();
72 }
Diese CCodierung wird in die Datei libjava.so(Linux) oder libjava.dll(Windows) kompiliert , die sich unter JAVA_HOME/jmods/java.base.jmod/lib/libjava.sofolgender Adresse befindet :
Referenz