À quoi sert le mot-clé natif en Java?

Réponses:

343

Le nativemot-clé est appliqué à une méthode pour indiquer que la méthode est implémentée en code natif à l'aide de JNI (Java Native Interface).

SLaks
la source
3
L'implémentation réelle n'a pas besoin d'utiliser JNI. Certaines méthodes JRE sont gérées intrinsèquement par la JVM. En fait, il n'est même pas obligatoire que l'implémentation soit en fait du code natif . Il est simplement «implémenté dans un langage autre que le langage de programmation Java» .
Holger
444

Exemple exécutable minimal

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));
    }
}

Principal c

#include <jni.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_square(
    JNIEnv *env, jobject obj, jint i) {
  return i * i;
}

Compiler et exécuter:

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

Production:

4

Testé sur Ubuntu 14.04 AMD64. Fonctionne également avec Oracle JDK 1.8.0_45.

Exemple sur GitHub pour jouer avec.

Les soulignements dans les noms de package / fichier Java doivent être échappés avec _1le nom de la fonction C, comme indiqué dans: Appel des fonctions JNI dans le nom de package Android contenant un soulignement

Interprétation

native vous permet de:

  • appeler une bibliothèque chargée dynamiquement compilée (ici écrite en C) avec du code d'assemblage arbitraire de Java
  • et obtenir des résultats en Java

Cela pourrait être utilisé pour:

  • écrire du code plus rapidement sur une section critique avec de meilleures instructions d'assemblage du processeur (pas portable CPU)
  • faire des appels système directs (pas portable OS)

avec le compromis d'une portabilité inférieure.

Il vous est également possible d'appeler Java à partir de C, mais vous devez d'abord créer une JVM en C: Comment appeler des fonctions Java à partir de C ++?

Des API d'extension natives analogues sont également présentes dans de nombreux autres "langages VM" pour les mêmes raisons, par exemple Python , Node.js , Ruby .

Android NDK

Le concept est exactement le même dans ce contexte, sauf que vous devez utiliser un passe-partout Android pour le configurer.

Le référentiel NDK officiel contient des exemples "canoniques" tels que l'application hello-jni:

En vous unzipune .apkavec NDK sur Android O, vous pouvez voir la pré-compilé .socorrespondant au code natif sous lib/arm64-v8a/libnative-lib.so.

TODO confirme: en outre, file /data/app/com.android.appname-*/oat/arm64/base.odexdit qu'il s'agit d'une bibliothèque partagée, qui je pense est le .dex AOT précompilé correspondant aux fichiers Java dans ART, voir aussi: Que sont les fichiers ODEX dans Android? Alors peut-être que Java est également exécuté via une nativeinterface?

Exemple dans OpenJDK 8

Trouvons trouver où Object#cloneest défini dans jdk8u60-b27.

Nous conclurons qu'il est implémenté par un nativeappel.

On trouve d'abord:

find . -name Object.java

ce qui nous amène à jdk / src / share / classes / java / lang / Object.java # l212 :

protected native Object clone() throws CloneNotSupportedException;

Vient maintenant la partie difficile, trouver où le clone est au milieu de toute l'indirection. La requête qui m'a aidé était:

find . -iname object.c

qui trouverait des fichiers C ou C ++ qui pourraient implémenter les méthodes natives d'Object. Cela nous amène à 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]));
}

ce qui nous amène au JVM_Clonesymbole:

grep -R JVM_Clone

ce qui nous amène à hotspot / src / share / vm / prims / jvm.cpp # l580 :

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
    JVMWrapper("JVM_Clone");

Après avoir développé un tas de macros, nous arrivons à la conclusion que c'est le point de définition.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
1
Excellente réponse. Juste une note: pour une static nativeméthode Java, le deuxième paramètre de la fonction C ++ est de type jclasset non jobject.
SR_
@SR_ merci pour l'info. Y a-t-il eu une erreur dans ma réponse, ou s'agit-il simplement de quelques informations supplémentaires?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
@Ciro c'est quelques informations supplémentaires pour ceux qui commencent par votre exemple (une réponse avec environ 300 sur SO peut servir de référence). J'ai eu une fonction avec une signature incorrecte appelée avec un gâchis sur la pile, sans aucune erreur signalée (à aucun moment de la compilation, du lien ou de l'exécution). Je trouve donc important de mentionner de faire attention à cette étape.
SR_
420

Il marque une méthode, qu'il sera implémenté dans d'autres langages, pas en Java. Il fonctionne avec JNI (Java Native Interface).

Des méthodes natives ont été utilisées dans le passé pour écrire des sections critiques pour les performances, mais avec l'accélération de Java, cela est désormais moins courant. Des méthodes natives sont actuellement nécessaires lorsque

  • Vous devez appeler une bibliothèque à partir de Java écrite dans une autre langue.

  • Vous devez accéder aux ressources système ou matérielles qui sont uniquement accessibles à partir de l'autre langue (généralement C). En fait, de nombreuses fonctions système qui interagissent avec un ordinateur réel (disque et réseau IO, par exemple) ne peuvent le faire que parce qu'elles appellent du code natif.

Voir aussi Spécification de l'interface native Java

Orhan Cinar
la source
3
C'est ce que je comprends, j'écris System.currentTimeMillis () (qui est natif) dans un fichier java et ensuite cela fonctionne, JNI appellera des bibliothèques ou certaines fonctions écrites en C ou C ++ ou en langage assembleur, puis retournera une valeur à mon code java . ex: ici la méthode currentTimeMillis invoque un code natif à l'aide de JNI et ce code natif parle à la ressource système ex: un temporisateur assis sur la carte mère et obtenant ainsi une valeur de retour (heure système). corrigez-moi, s'il vous plaît?
MKod
4
Les méthodes @MKod comme currentTimeMillisfont partie du JDK et sont annotées nativecar l'implémentation se trouve dans le code source du JDK lui-même. Il est très peu probable que l'implémentation utilise le langage d'assemblage; il appelle probablement une méthode API du système d'exploitation sur lequel la JVM s'exécute. Par exemple, sous Windows, il peut appeler une méthode DLL GetSystemTimedans kernel32.dll. Sur un autre OS, il aura une implémentation différente. Cependant, lorsque vous utilisez nativeune méthode que vous écrivez (par opposition à une méthode JDK), vous devez fournir l'implémentation à l'aide de JNI.
Adam Burley du
Cette déclaration est importante pour le mot-clé natif ... "Vous devez accéder aux ressources système ou matérielles qui ne sont accessibles que dans l'autre langue (généralement C)".
atiqkhaled
@Kidburla Puis-je vous demander ce que vous entendez par «l'implémentation est dans le code source JDK lui-même»? currentTimeMillisest marqué comme natif java.lang.Systemdonc il utilise JNI, n'est-ce pas?
flow2k
1
@ flow2k oui, ce que vous avez dit est probablement vrai, je ne sais pas pourquoi j'ai dit cela dans mon commentaire (il y a plus de 2 ans)
Adam Burley
59

Directement à partir de la spécification du langage Java :

Méthode nativeimplémentée dans du code dépendant de la plate-forme, généralement écrit dans un autre langage de programmation tel que C, C ++, FORTRAN ou langage d'assemblage. Le corps d'une nativeméthode n'est donné que par un point-virgule, indiquant que l'implémentation est omise, au lieu d'un bloc.

Pops
la source
19

Comme SLaks a répondu, le nativemot clé est pour appeler le code natif.

Il est également utilisé par GWT pour implémenter des méthodes javascript.

Melv
la source
13

les fonctions qui implémentent du code natif sont déclarées natives.

La Java Native Interface (JNI) est un cadre de programmation qui permet au code Java exécuté dans une machine virtuelle Java (JVM) d'appeler et d'être appelé par des applications natives (programmes spécifiques à une plate-forme matérielle et de système d'exploitation) et des bibliothèques écrites en d'autres langages tels que C, C ++ et l'assemblage.

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

Adelin
la source
8

NATIVE est Non access modifier.it peut être appliqué uniquement à METHOD. Il indique l'implémentation PLATFORM-DEPENDENT de la méthode ou du code.

Reetika
la source
6

native est un mot clé en java, qui est utilisé pour créer une structure (méthode) non implémentée comme abstraite, mais ce serait une plate-forme dépendante telle que le code natif et exécutée à partir de la pile native et non de la pile java.

Sarfaraz Ahamad Shaikh
la source
6
  • native est un mot-clé en java, il indique la plateforme dépendante.
  • nativeLes méthodes sont des interfaces entre Java ( JNI ) et d'autres langages de programmation.
Premraj
la source
3

La nativeméthode Java fournit un mécanisme permettant au code Java d'appeler le code natif du système d'exploitation, pour des raisons fonctionnelles ou de performances.

Exemple:

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();

Dans le correspondant Runtime.class fichier dans OpenJDK, situé dans JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class, contient ces méthodes et les a marquées avec ACC_NATIVE( 0x0100), et ces méthodes ne contiennent pas l' attribut Code , ce qui signifie que ces méthodes n'ont pas de logique de codage réelle dans le Runtime.classfichier:

  • Méthode 13 availableProcessors: balisé comme natif et sans attribut Code
  • Méthode 14 freeMemory: étiqueté comme natif et sans attribut Code
  • Méthode 15 totalMemory: étiqueté comme natif et sans attribut Code
  • Méthode 16 maxMemory: étiqueté comme natif et sans attribut Code
  • Méthode 17 gc: étiqueté comme natif et sans attribut Code

entrez la description de l'image ici

En fait, la logique de codage est dans le correspondant fichier Runtime.c :

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  }

Et ces Ccodages sont compilés dans le fichier libjava.so(Linux) ou libjava.dll(Windows), situé à JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

entrez la description de l'image ici

entrez la description de l'image ici

Référence

Heureux
la source