Wofür ist das native Schlüsselwort in Java?


Antworten:


343

Das nativeSchlüsselwort wird auf eine Methode angewendet, um anzugeben, dass die Methode mithilfe von JNI (Java Native Interface) in nativem Code implementiert ist.


3
Die eigentliche Implementierung muss kein JNI verwenden. Bestimmte JRE-Methoden werden von der JVM eigenständig behandelt. Tatsächlich ist es nicht einmal obligatorisch, dass die Implementierung tatsächlich nativer Code ist. Es ist nur "in einer anderen Sprache als der Java-Programmiersprache implementiert" .
Holger

444

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:

  • Rufen Sie eine kompilierte dynamisch geladene Bibliothek (hier in C geschrieben) mit beliebigem Assembler-Code aus Java auf
  • und erhalten Sie Ergebnisse zurück in Java

Dies könnte verwendet werden, um:

  • Schreiben Sie schnelleren Code in einen kritischen Abschnitt mit besseren Anweisungen zum Zusammenbau der CPU (nicht tragbar für die CPU).
  • direkte Systemaufrufe tätigen (nicht tragbares Betriebssystem)

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.


1
Hervorragende Antwort. Nur eine Fußnote: Für eine static nativeJava-Methode ist der zweite Parameter der C ++ - Funktion vom Typ jclassund nicht vom Typ jobject.
SR_

@ SR_ danke für die Info. Gab es einen Fehler in meiner Antwort oder sind es nur einige zusätzliche Informationen?
Ciro Santilli 法轮功 冠状 病 六四 事件 19

2
@Ciro Es sind einige zusätzliche Informationen für diejenigen, die mit Ihrem Beispiel beginnen (eine Antwort mit ungefähr 300 auf SO kann als Referenz dienen). Ich hatte eine Funktion mit einer falschen Signatur, die mit einem Durcheinander auf dem Stapel aufgerufen wurde, ohne dass ein Fehler gemeldet wurde (zu Kompilierungs-, Link- oder Laufzeitzeiten). Daher finde ich es wichtig zu erwähnen, bei diesem Schritt vorsichtig zu sein.
SR_

419

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


3
Nach meinem Verständnis schreibe ich System.currentTimeMillis () (nativ) in eine Java-Datei. Damit dies funktioniert, ruft JNI Bibliotheken oder einige Funktionen auf, die in C oder C ++ oder in Assemblersprache geschrieben sind, und gibt dann einen Wert an meinen Java-Code zurück . Beispiel: Hier ruft die currentTimeMillis-Methode mithilfe von JNI einen nativen Code auf und dieser native Code kommuniziert mit der Systemressource. Beispiel: Ein Timer, der auf dem Motherboard sitzt und somit den Rückgabewert (Systemzeit) erhält. korrigiere mich bitte?
MKod

4
@ MKK-Methoden wie 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.
Adam Burley

Diese Anweisung ist wichtig für das Schlüsselwort Native ... "Sie müssen auf System- oder Hardwareressourcen zugreifen, die nur über die andere Sprache (normalerweise C) erreichbar sind."
Atiqkhaled

@Kidburla Darf ich fragen, was Sie unter "Implementierung im JDK-Quellcode selbst" verstehen? currentTimeMillisist in als nativ markiert java.lang.System, verwendet also JNI, stimmt das nicht?
flow2k

1
@ flow2k ja, was Sie gesagt haben, ist wahrscheinlich wahr, ich bin nicht sicher, warum ich das in meinem Kommentar (vor mehr als 2 Jahren) gesagt habe
Adam Burley

59

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 einer nativeMethode wird nur als Semikolon angegeben, was darauf hinweist, dass die Implementierung anstelle eines Blocks weggelassen wird.


19

Wie SLaks antwortete, dient das nativeSchlüsselwort zum Aufrufen von nativem Code.

Es wird auch von GWT zur Implementierung von Javascript-Methoden verwendet.


13

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.

http://en.wikipedia.org/wiki/Java_Native_Interface


8

NATIVE ist kein Zugriffsmodifikator. Es kann nur auf METHOD angewendet werden. Es zeigt die PLATFORM-ABHÄNGIGE Implementierung der Methode oder des Codes an.


6

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.


6
  • native ist ein Schlüsselwort in Java, es zeigt plattformabhängig an.
  • nativeMethoden fungieren als Schnittstelle zwischen Java ( JNI ) und anderen Programmiersprachen.

3

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:

  • Methode 13 availableProcessors: als nativ und ohne Code-Attribut markiert
  • Methode 14 freeMemory: als nativ und ohne Code-Attribut markiert
  • Methode 15 totalMemory: als nativ und ohne Code-Attribut markiert
  • Methode 16 maxMemory: als nativ und ohne Code-Attribut markiert
  • Methode 17 gc: als nativ und ohne Code-Attribut markiert

Geben Sie hier die Bildbeschreibung ein

Die 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 :

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Referenz

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.