2009-02-17 6 views
33

Si nous regardons la classe Java Object alors nous pouvons trouver quelques-unes des méthodes telles que:Qu'est-ce qu'une implémentation native dans Java?

public native int hashCode() 
protected native Object clone() 

Quels sont ces indigènes et comment ces méthodes fonctionnent?

Répondre

34

Ces méthodes sont Intrinsic ou écrites en dehors de Java en code "natif", c'est-à-dire spécifiques à la machine donnée.

Ceux que vous mentionnez sont Intrinsèque et une partie du JDK mais vous pouvez aussi écrire vous-même des méthodes natives en utilisant la Java Native Interface (JNI). Cela devrait normalement utiliser C pour écrire les méthodes, mais beaucoup d'autres langages, tels que python, vous permettent d'écrire des méthodes de cette façon assez facilement. Le code est écrit de cette façon soit pour les performances, soit parce qu'il doit accéder à une infrastructure spécifique à la plate-forme, ce qui ne peut pas être fait en Java.

Dans le cas de hashcode(), ceci est implémenté par la JVM. C'est parce que souvent le hashcode sera lié à quelque chose que la JVM connaît. Sur les JVM précoces, ceci était lié à l'emplacement de l'objet en mémoire - sur d'autres JVM, l'Object peut se déplacer en mémoire, et donc un schéma plus compliqué (mais toujours très rapide) peut être utilisé.

+6

Si hashcode() est implémenté par JVM uniquement, pourquoi faut-il qu'il soit * natif *? Que voulez-vous dire exactement par * intrinsèque * ici? – Geek

11

Les méthodes natives sont implémentées principalement en C et compilées en code natif qui s'exécute directement sur la machine. Ceci est en contraste avec les méthodes normales, qui sont implémentées en Java et compilées en Java byte code, qui est exécutée par Java Virtual Machine (JVM). Pour faire l'interface avec Java, vous devez utiliser le Java Native Interface (JNI).

Le code natif est principalement nécessaire pour accéder aux données de bas niveau. Dans le cas de hashCode c'est l'adresse de l'objet en mémoire. Ma conjecture pour clone est qu'il copie la mémoire brute d'un objet donné à l'objet cloné. D'autres utilisations du code natif sont pour l'accès aux fonctionnalités du système d'exploitation ou au matériel. L'inconvénient de l'utilisation du code natif est que vous perdez la sécurité et la sécurité de la JVM, c'est-à-dire que votre programme peut tomber en panne ou présenter des failles de sécurité dues à des bogues dans le code natif.

17

La plupart des méthodes natives sont implémentées en utilisant JNI comme mentionné dans d'autres réponses. Cependant, les méthodes critiques de performance telles que Object.hashCode sont généralement implémentées en tant qu'intrinsèque. Lorsque le code d'octet est compilé en code machine, le compilateur Java reconnaît l'appel de méthode et insère le code approprié directement. Cela va évidemment être beaucoup plus rapide que de passer par JNI pour une méthode triviale.

Beaucoup de gens affirmeront que Object.hashCode retournera l'adresse de la représentation de l'objet en mémoire. Dans les implémentations modernes, les objets se déplacent réellement dans la mémoire. Au lieu de cela, une zone de l'en-tête de l'objet est utilisée pour stocker la valeur, qui peut être dérivée paresseusement de l'adresse mémoire au moment où la valeur est demandée en premier.

+2

Pour plus de détails [visiter] (http://stackoverflow.com/a/13860488/390695) –

10

Quels sont ces indigènes et comment ces méthodes fonctionnent-elles?

exemple minimal pour rendre les choses plus claires:

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

Compilez et exécutez:

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 

Sortie:

4 

testé sur Ubuntu 14.04. A également travaillé avec Oracle JDK 1.8.0_45.

Example on GitHub pour que vous puissiez jouer avec.

interprétation:

Il vous permet de:

  • appel a compilé bibliothèque chargée dynamiquement (ici écrit en C) avec le code d'assemblage arbitraire de Java
  • et obtenir des résultats de retour en Java

Ceci peut être utilisé pour:

  • écrire plus vite code sur une section critique avec de meilleures instructions d'assemblage CPU (pas de portables CPU)
  • faire des appels système direct (non OS portable)

avec le compromis entre la Basse portabilité.

Il est également possible pour vous d'appeler Java à partir de C, mais vous devez d'abord créer une machine virtuelle Java en C: How to call Java functions from C++?

Exemple dans le OpenJDK 8

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

D'abord, nous trouvons:

find . -name Object.java 

qui nous conduit à jdk/src/share/classes/java/lang/Object.java#l212:

protected native Object clone() throws CloneNotSupportedException; 

Maintenant vient la partie la plus difficile, trouver où clone est parmi tous les 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 de l'objet.Il nous conduit à 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])); 
} 

qui nous conduit au symbole JVM_Clone:

grep -R JVM_Clone 

qui nous conduit à 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 venons à la conclusion que c'est le point de définition.