Durante questo puzzle (è un gioco a quiz su parole chiave Java), mi sono imbattuto nella native
parola chiave.
A cosa serve la parola chiave nativa in Java?
Durante questo puzzle (è un gioco a quiz su parole chiave Java), mi sono imbattuto nella native
parola chiave.
A cosa serve la parola chiave nativa in Java?
Risposte:
La native
parola chiave viene applicata a un metodo per indicare che il metodo è implementato nel codice nativo utilizzando JNI (Java Native Interface).
Esempio eseguibile minimo
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));
}
}
main.c
#include <jni.h>
#include "Main.h"
JNIEXPORT jint JNICALL Java_Main_square(
JNIEnv *env, jobject obj, jint i) {
return i * i;
}
Compila ed esegui:
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
Produzione:
4
Testato su Ubuntu 14.04 AMD64. Ha funzionato anche con Oracle JDK 1.8.0_45.
Esempio su GitHub con cui giocare.
I caratteri di sottolineatura nei nomi dei pacchetti / file Java devono essere esclusi con _1
il nome della funzione C come indicato in: Richiamare le funzioni JNI nel nome del pacchetto Android contenente il trattino basso
Interpretazione
native
ti permette di:
Questo potrebbe essere usato per:
con il compromesso della portabilità inferiore.
È anche possibile chiamare Java da C, ma è necessario prima creare una JVM in C: Come chiamare le funzioni Java da C ++?
API analoghe con estensione nativa sono presenti anche in molti altri "linguaggi VM" per gli stessi motivi, ad esempio Python , Node.js , Ruby .
Android NDK
Il concetto è esattamente lo stesso in questo contesto, tranne per il fatto che è necessario utilizzare il boilerplate Android per configurarlo.
Il repository NDK ufficiale contiene esempi "canonici" come l'app hello-jni:
In te unzip
e .apk
con NDK su Android O, puoi vedere il pre-compilato .so
che corrisponde al codice nativo sotto lib/arm64-v8a/libnative-lib.so
.
Conferma TODO: inoltre, file /data/app/com.android.appname-*/oat/arm64/base.odex
dice che è una libreria condivisa, che penso sia il .dex precompilato AOT corrispondente ai file Java in ART, vedi anche: Cosa sono i file ODEX in Android? Quindi forse Java viene effettivamente eseguito anche tramite native
un'interfaccia?
Esempio in OpenJDK 8
Scopriamo dove Object#clone
è definito in jdk8u60-b27.
Concluderemo che è implementato con una native
chiamata.
Innanzitutto troviamo:
find . -name Object.java
che ci porta a jdk / src / share / classes / java / lang / Object.java # l212 :
protected native Object clone() throws CloneNotSupportedException;
Ora arriva la parte difficile, trovando dove si trova il clone in mezzo a tutti i riferimenti indiretti. La domanda che mi ha aiutato è stata:
find . -iname object.c
che troverebbe i file C o C ++ che potrebbero implementare i metodi nativi di Object. Ci porta a 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]));
}
che ci porta al JVM_Clone
simbolo:
grep -R JVM_Clone
che ci porta a hotspot / src / share / vm / prims / jvm.cpp # l580 :
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
Dopo aver ampliato un gruppo di macro, arriviamo alla conclusione che questo è il punto di definizione.
static
native
metodo Java, il secondo parametro della funzione C ++ è di tipo jclass
e non jobject
.
Segna un metodo, che verrà implementato in altre lingue, non in Java. Funziona insieme a JNI (Java Native Interface).
In passato sono stati utilizzati metodi nativi per scrivere sezioni critiche in termini di prestazioni, ma con Java sempre più veloce ora è meno comune. I metodi nativi sono attualmente necessari quando
È necessario chiamare una libreria da Java scritta in un'altra lingua.
È necessario accedere alle risorse di sistema o hardware che sono raggiungibili solo dall'altra lingua (in genere C). In realtà, molte funzioni di sistema che interagiscono con il computer reale (IO del disco e della rete, ad esempio) possono farlo solo perché chiamano codice nativo.
Vedere anche Specifiche dell'interfaccia nativa Java
currentTimeMillis
fanno parte del JDK e sono annotati native
perché l'implementazione è nel codice sorgente JDK stesso. È molto improbabile che l'implementazione usi il linguaggio assembly; probabilmente chiama un metodo API del sistema operativo su cui è in esecuzione la JVM. Ad esempio su Windows potrebbe chiamare un metodo DLL GetSystemTime
in kernel32.dll. Su un altro sistema operativo avrà un'implementazione diversa. Tuttavia, quando usi native
un metodo che stai scrivendo (al contrario di un metodo JDK) devi fornire l'implementazione usando JNI.
currentTimeMillis
è contrassegnato come nativo in java.lang.System
quindi utilizza JNI, non è vero?
Direttamente dal l' Specification linguaggio Java :
Un metodo
native
implementato in codice dipendente dalla piattaforma, in genere scritto in un altro linguaggio di programmazione come C, C ++, FORTRAN o linguaggio assembly. Il corpo di unnative
metodo viene fornito solo come punto e virgola, a indicare che l'implementazione è stata omessa, anziché un blocco.
le funzioni che implementano il codice nativo sono dichiarate native.
Java Native Interface (JNI) è un framework di programmazione che consente al codice Java in esecuzione in una Java Virtual Machine (JVM) di chiamare e di essere chiamato da applicazioni native (programmi specifici di una piattaforma hardware e di sistema operativo) e librerie scritte in altri linguaggi come C, C ++ e assembly.
native è una parola chiave in Java, che viene utilizzata per rendere la struttura (metodo) non implementata come astratta ma sarebbe una piattaforma dipendente come codice nativo ed eseguita dallo stack nativo non dallo stack Java.
Giava native
metodo fornisce un meccanismo per il codice Java per chiamare il codice nativo del sistema operativo, a causa di motivi funzionali o di prestazioni.
Esempio:
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();
Nel Runtime.class
file corrispondente in OpenJDK, che si trova in JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class
, contiene questi metodi e li ha taggati con ACC_NATIVE
( 0x0100
), e questi metodi non contengono l' attributo Code , il che significa che questi metodi non hanno alcuna logica di codifica effettiva nel Runtime.class
file:
availableProcessors
: taggato come attributo nativo e senza codicefreeMemory
: taggato come attributo nativo e senza codicetotalMemory
: taggato come attributo nativo e senza codicemaxMemory
: taggato come attributo nativo e senza codicegc
: taggato come attributo nativo e senza codiceLa logica di codifica infatti si trova nel file Runtime.c corrispondente :
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 }
E questa C
codifica viene compilata nel file libjava.so
(Linux) o libjava.dll
(Windows), che si trova in JAVA_HOME/jmods/java.base.jmod/lib/libjava.so
:
Riferimento