![]() |
Mon site perso a changé d'adresse. Si rien ne se passe cliquez sur le lien ci-dessus. |
|
|
|
|
|
|
Développons en Java v 0.85 béta | |
| Copyright (C) 1999-2005 Jean-Michel DOUDOUX |
![]() |
![]() |
![]() |
JNI est l'acronyme de Java Native Interface. C'est une technologie qui permet d'utiliser du code natif dans une classe Java notamment C.
L'inconvénient majeur de cette technologie est d'annuler la portabilité du code Java. En contre partie cette technologie peut être très utile dans plusieurs cas :
La mise en oeuvre de JNI nécessite plusieurs étapes :
Le format de la bibliothèque est donc dépendante du système d'exploitation pour lequel elle est développée : .dll pour les systèmes de type Windows, .so pour les système de type Unix, ...
Ce chapitre contient plusieurs sections :
La déclaration dans le code source Java est très facile puisqu'il suffit de déclarer la signature de la méthode avec le modificateur native. Le modificateur permet au compilateur de savoir que cette méthode est contenue dans une bibliothèque native.
Il ne doit pas y avoir d'implémentation même un corps vide pour une méthode déclarée native.
| Exemple : |
|
Pour pouvoir utiliser une méthode native, il faut tout d'abord charger la bibliothèque. Pour réaliser ce chargement, il utiliser la méthode statique loadLibrary() de la classe system. Il faut obligatoirement s'assurer que la bibliothèque est chargée avant le premier appel de la méthode native.
Le plus simple pour assurer ce chargement est de le demander dans un morceau de code d'initialisation statique de la classe.
| Exemple : |
|
Le nom de la bibliothèque fournie en paramètre doit être indépendant de la plate-forme utilisée : il faut préciser le nom de la bibliothèque sans son extension. Le nom sera automatiquement adapté selon le système d'exploitation sur lequel le code Java est exécuté.
L'utilisation de la méthode native dans le code Java se fait de la même façon qu'une méthode classique.
| Exemple : |
|
L'outil javah fourni avec le JDK permet de générer un fichier d'en-tête qui va contenir la définition dans le langage C des fonctions correspondant aux méthodes déclarées native dans le source Java.
Javah utilise le byte code pour générer le fichier .h. Il faut donc que la classe Java soit préalablement compilée.
La syntaxe est donc : javah –jni nom_fichier_sans_extension
| Exemple : |
|
Le fichier TestJNI1.h généré est le suivant :
| Exemple : |
|
Le nom de chaque fonction native respecte le format suivant :
Java_nomPleinementQualifieDelaClasse_NomDeLaMethode
Ce fichier doit être utilisé dans l'implémentation du code de la fontion.
Même si la méthode native est déclarée sans paramètre, il y a toujours deux paramètres passés à la fonction native :
La bibliothèque contenant la ou les fonctions qui seront appelées doit être écrite dans un langage (c ou c++) et compilée.
Pour l'écriture en C, facilitée par la génération du fichier.h, il est nécessaire en plus des includes liées au code des fonctions d'inclure deux fichiers d'en-tête :
| Exemple : TestJNI.c |
|
Il faut compiler ce fichier source sous la forme d'un fichier objet .o
| Exemple : avec MinGW sous Windows |
|
Il faut ensuite définir un fichier .def qui contient la définition des fonctions exportées par la bibliothèque
| Exemple : TestJNI.def |
|
Il ne reste plus qu'à générer la dll.
| Exemple : TestJNI.def |
|
Il ne reste plus qu'à exécuter le code Java dans une machine virtuelle.
| Exemple : |
|
Il est intéressant de noter que tant que la signature de la méthode native ne change pas, il est inutile de recompiler la classe Java si l& fonction dans la bibliothèque est modifiée et recompilée.
Une méthode a quasiment toujours besoin de paramètres et souvent besoin de retourner une valeur.
Cette section va définir et utiliser une méthode native qui ajoute deux entiers et renvoie le résultat de l'addition.
| Exemple : le code Java |
|
La déclaration de la méthode n'a rien de particulier hormis le modificateur native.
La signature de la fonction dans le fichier .h tient des paramètres.
| Exemple : |
|
Les deux paramètres sont ajoutés dans la signature de la fonction avec un type particulier jint, défini avec un typedef dans le fichier jni.h. Il y a d'ailleurs des définitions pour toutes les primitives.
| Primitive Java | Type natif |
| boolean | jboolean |
| byte | jbyte |
| char | jchar |
| double | jdouble |
| int | jint |
| float | jfloat |
| long | jlong |
| short | jshort |
| void | void |
Il suffit ensuite d'écrire l'implémentation du code natif.
| Exemple : |
|
Il faut ensuite compiler le code :
| Exemple : |
|
Il faut définir le fichier .def : l'exemple ci dessous va construire une bibliothèque qui va contenir les fonctions natives des deux classes Java précédemment définies.
| Exemple : |
|
Il suffit de générer la bibilothèque.
| Exemple : |
|
Il ne reste plus qu'a exécuter le code Java
| Exemple : |
|
Les objets sont passés par référence en utilisant une variable de type jobject. Plusieurs autres type sont prédéfinis par JNI pour des objets fréquemment utilisés :
| Objet C | Objet Java |
| jobject | java.lang.object |
| jstring | java.lang.String |
| jclass | java.lang.Class |
| jthrowable | java.lang.Throwable |
| jarray | type de base pour les tableaux |
| jintArray | int[] |
| jlongArray | long[] |
| jfloatArray | float[] |
| jdoubleArray | double[] |
| jobjectArray | Object[] |
| jbooleanArray | boolean[] |
| jbyteArray | byte[] |
| jcharArray | char[] |
| jshortArray | short[] |
| Exemple : concaténation de deux chaînes de caractères |
|
La déclaration de la fonction native dans le fichier TestJNI3.h est la suivante :
| Exemple : |
|
Pour utiliser les paramètres de type jstring dans le code natif, il faut les transformer en utilisant des fonctions proposées par l'interface de type JNIEnv car le type String de Java n'est pas directement compatible avec les chaînes de caractères C (char *). Il existe des fonctions pour transformer des chaînes codées en UTF-8 ou en Unicode.
Les méthodes pour traiter les chaînes au format UTF-8 sont :
Les méthodes équivalentes pour les chaines de caractères au format unicode sont : GetStringChars(), NewString(), GetStringUTFLength() et ReleaseStringChars()
| Exemple : TestJNI3.c |
|
Attention : ce code est très simpliste car il ne vérifie pas un éventuel débordement du tableau résultat.
Après la compilation des différents éléments, l'exécution affiche le résultat escompté.
| Exemple : |
|
|
|
|
|
|
|
Développons en Java v 0.85 béta | ||
| Copyright (C) 1999-2005 Jean-Michel DOUDOUX |