2009-06-18 8 views

Répondre

90

Les autres réponses sont techniquement correctes, mais pas très utiles pour quelqu'un sans expérience JNI. :-)

Normalement, pour que la JVM trouve vos fonctions natives, vous devez les nommer d'une certaine manière. par exemple, pour java.lang.Object.registerNatives, la fonction C correspondante est nommée Java_java_lang_Object_registerNatives. En utilisant registerNatives (ou plutôt, la fonction JNI RegisterNatives), vous pouvez nommer vos fonctions C ce que vous voulez.

Voici le code C associé (de OpenJDK 6):

static JNINativeMethod methods[] = { 
    {"hashCode", "()I",     (void *)&JVM_IHashCode}, 
    {"wait",  "(J)V",     (void *)&JVM_MonitorWait}, 
    {"notify",  "()V",     (void *)&JVM_MonitorNotify}, 
    {"notifyAll", "()V",     (void *)&JVM_MonitorNotifyAll}, 
    {"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])); 
} 

(Notez que Object.getClass est pas dans la liste, il sera toujours appelé par le nom « standard » de Java_java_lang_Object_getClass.) Pour les fonctions listées, les fonctions C associées sont listées dans cette table, ce qui est plus pratique que d'écrire un tas de fonctions de transfert. L'enregistrement de fonctions natives est également utile si vous incorporez Java dans votre programme C et que vous voulez lier des fonctions dans l'application elle-même (par opposition à une bibliothèque partagée), ou si les fonctions utilisées ne sont pas "exportées" ", puisque ceux-ci ne seraient normalement pas trouvés par le mécanisme de recherche de méthode standard. L'enregistrement de fonctions natives peut également être utilisé pour "relier" une méthode native à une autre fonction C (utile si votre programme supporte dynamiquement les modules de chargement et de déchargement, par exemple).

J'encourage tout le monde à lire le JNI book, qui en parle et bien plus encore. :-)

+1

Vous avez écrit un nom de fonction JNI entièrement décoré, ce qui le rend confus: 'Java_java_lang_Object_registerNatives' appelé automatiquement par VM, ou c/C++ code doit appeler cette fonction et il n'y a pas besoin de tout ce gobblighook java – Pavel

+0

@Pavel Par défaut, un La méthode native 'methodName' dans la classe' fully.qualified.ClassName' est recherchée sous le nom C 'Java_fully_qualified_ClassName_methodName' (que votre code C-side doit exporter). Vous pouvez appeler la méthode 'RegisterNatives' de' JNIEnv' pour remplacer ce lien. En d'autres termes, si vous n'utilisez pas d'abord "RegisterNatives", "tout ce java gobblygook" [sic] est requis. –

+0

Ah, ok, donc en exportant seulement 1 fonction 'Java_java_lang_Object_registerNatives' je peux réellement lier tous mes trucs JNI en vérifiant la valeur de' cls'. J'ai raté la partie que registerNatives fait réellement partie de Java elle-même. Alors ... quand une classe est sur le point d'être utilisée, quel est l'ordre des actions que la JVM utilise pour lier les indigènes? Il semble que si les indigènes ne sont pas encore enregistrés (à partir de c/C++), alors la JVM vérifie tous ces noms exportés, s'ils ne sont pas présents, alors il essaye d'utiliser Object.registerNatives (ou inversement?). Au fait, le lien du livre jni est mort. – Pavel

-9

Depuis que vous avez regardé le code source pour le trouver, il est assez facile à deviner n'est pas?

C'est une méthode native, et elle s'appelle registerNatives, donc je suppose qu'elle enregistre des objets avec la plate-forme sous-jacente.

Il est également privé, donc il n'y a probablement pas de quoi s'inquiéter.

+20

Vous devez être un programmeur à code source fermé ("aller de l'avant, rien à regarder"), pas habitué à l'idée que les gens veulent vraiment savoir ce qui se passe "sous les couvertures". Assez dit. :-P –

+2

Darn, était-ce évident, n'est-ce pas? – aberrant80

8

Ce qui pourrait être légèrement déroutant est que le code indiqué pour java.lang.Object.registerNatives dans une réponse précédente est juste un exemple de la façon d'enregistrer des fonctions natives. C'est le code qui (dans l'implémentation d'OpenJDK) enregistre les fonctions natives pour la classe Object. Pour enregistrer des fonctions natives pour votre propre classe, vous devez appeler la fonction JNI RegisterNatives à partir du code natif dans votre propre bibliothèque. Cela peut sembler un peu circulaire, mais il y a plusieurs façons de briser la boucle.

  1. Suivez l'exemple de cette mise en œuvre de la classe Object:

    a. Dans votre classe Java, déclarez une méthode native (de préférence statique) nommée registerNatives (ou tout autre nom, peu importe).

    b. Dans votre code natif, définissez une fonction nommée Java_<your fully qualified class name>_registerNatives, qui contient un appel à la fonction JNI RegisterNatives.

    c. Assurez-vous que dans votre code Java, votre méthode Java registerNatives est appelée avant tout appel à d'autres méthodes natives.

OU

  1. Utilisez JNI_OnLoad

    a. Dans votre bibliothèque native, définissez une fonction jint JNI_OnLoad(JavaVM *vm, void *reserved). Dans le corps de cette fonction, appelez la fonction JNI RegisterNatives.

    b. La machine virtuelle Java recherchera automatiquement et appellera JNI_OnLoad lorsque votre bibliothèque native est chargée par System.loadLibrary, que vous devriez déjà appeler, probablement dans un initialiseur statique pour votre classe. (Vous obtenez le pointeur env nécessaire en appelant la fonction GetEnv dans le tableau que les points de pointeur vm à.)