A cosa serve la parola chiave nativa in Java?


Risposte:



444

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

  • chiama una libreria compilata caricata dinamicamente (qui scritta in C) con codice assembly arbitrario da Java
  • e ottenere risultati in Java

Questo potrebbe essere usato per:

  • scrivere codice più veloce in una sezione critica con migliori istruzioni di assemblaggio della CPU (non CPU portatili)
  • effettuare chiamate di sistema dirette (non portatili OS)

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 unzipe .apkcon NDK su Android O, puoi vedere il pre-compilato .soche corrisponde al codice nativo sotto lib/arm64-v8a/libnative-lib.so.

Conferma TODO: inoltre, file /data/app/com.android.appname-*/oat/arm64/base.odexdice 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 nativeun'interfaccia?

Esempio in OpenJDK 8

Scopriamo dove Object#cloneè definito in jdk8u60-b27.

Concluderemo che è implementato con una nativechiamata.

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

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.


1
Risposta eccellente. Solo una nota a piè di pagina: per un static nativemetodo Java, il secondo parametro della funzione C ++ è di tipo jclasse non jobject.
SR_18

@SR_ grazie per le informazioni. C'è stato un errore nella mia risposta o sono solo alcune informazioni extra?
Ciro Santilli 19 冠状 病 六四 事件 法轮功

2
@Ciro sono alcune informazioni extra per coloro che iniziano con il tuo esempio (una risposta con circa 300 su SO può servire da riferimento). Ho avuto una funzione con una firma errata chiamata con un pasticcio nello stack, senza errori segnalati (in nessuno dei tempi di compilazione, collegamento o esecuzione). Quindi trovo importante menzionare di fare attenzione in questo passaggio.
SR_

419

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


3
Questa è la mia comprensione, scrivo System.currentTimeMillis () (che è nativo) nel file Java e quindi per funzionare, JNI chiamerà le librerie o alcune funzioni scritte in C o C ++ o linguaggio assembly e quindi restituirà un valore al mio codice Java . es: qui il metodo currentTimeMillis richiama un codice nativo con l'aiuto di JNI e quel codice nativo comunica con la risorsa di sistema es: un timer seduto sulla scheda madre e quindi ottenendo un valore di ritorno (ora del sistema). correggimi, per favore?
MKod,

4
I metodi @MKod come currentTimeMillisfanno parte del JDK e sono annotati nativeperché 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 GetSystemTimein kernel32.dll. Su un altro sistema operativo avrà un'implementazione diversa. Tuttavia, quando usi nativeun metodo che stai scrivendo (al contrario di un metodo JDK) devi fornire l'implementazione usando JNI.
Adam Burley,

Questa affermazione è importante per la parola chiave nativa ... "È necessario accedere alle risorse di sistema o hardware che sono raggiungibili solo dall'altra lingua (in genere C)".
atiqkhaled il

@Kidburla Posso chiederti cosa intendi con "l'implementazione è nel codice sorgente JDK stesso"? currentTimeMillisè contrassegnato come nativo in java.lang.Systemquindi utilizza JNI, non è vero?
flow2k

1
@ flow2k sì, quello che hai detto è probabilmente vero, non sono sicuro del perché l'ho detto nel mio commento (più di 2 anni fa)
Adam Burley il

59

Direttamente dal l' Specification linguaggio Java :

Un metodo nativeimplementato in codice dipendente dalla piattaforma, in genere scritto in un altro linguaggio di programmazione come C, C ++, FORTRAN o linguaggio assembly. Il corpo di un nativemetodo viene fornito solo come punto e virgola, a indicare che l'implementazione è stata omessa, anziché un blocco.


19

Come ha risposto SLaks, la nativeparola chiave è per chiamare il codice nativo.

Utilizzato anche da GWT per l'implementazione di metodi javascript.


13

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.

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


8

NATIVE è Modificatore di non accesso.it può essere applicato solo a METODO. Indica l'implementazione PLATFORM-DEPENDENT del metodo o del codice.


6

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.


6
  • native è una parola chiave in Java, indica dipendente dalla piattaforma.
  • nativei metodi funzionano come interfaccia tra Java ( JNI ) e altri linguaggi di programmazione.

3

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.classfile 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.classfile:

  • Metodo 13 availableProcessors: taggato come attributo nativo e senza codice
  • Metodo 14 freeMemory: taggato come attributo nativo e senza codice
  • Metodo 15 totalMemory: taggato come attributo nativo e senza codice
  • Metodo 16 maxMemory: taggato come attributo nativo e senza codice
  • Metodo 17 gc: taggato come attributo nativo e senza codice

inserisci qui la descrizione dell'immagine

La 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 Ccodifica viene compilata nel file libjava.so(Linux) o libjava.dll(Windows), che si trova in JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Riferimento

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.