Développer en Java/Faire appel à du code natif
Java est capable d'utiliser du code natif pour réaliser certaines fonctions spécifiques à un système d'exploitation (en général des fonctions de bas niveau telle que la gestion des utilisateurs, ...). Une partie de l'API Java a recourt à du code natif (accès aux fichiers, interface graphique).
Les applications Java peuvent également faire appel à du code natif pour étendre les possibilités de l'application, ou pour améliorer les performances de l'application. L'inconvénient majeur est que cela amoindrie la portabilité de celle-ci.
Principes
modifierL'appel au code natif depuis Java se fait avec l'API JNI (Java Native Interface).
Côté Java
modifierL'application Java peut faire appel à des méthodes déclarées avec le mot-clé native
et ne comportant pas de corps d'implémentation (comme les méthodes abstraites) car le code natif est dans un fichier séparé.
Côté code natif
modifierLe code natif doit fournir l'implémentation des méthodes déclarées comme native
dans les classes Java.
En théorie, il peut utiliser n'importe quel langage de programmation.
En pratique, le C et le C++ sont les plus utilisés.
De plus le JDK fournit l'outil javah
pour générer un fichier d'en-tête (*.h) à partir d'une classe Java compilée (*.class).
Ce fichier d'en-tête contient une déclaration pour chaque méthode déclarée avec le mot clé native
.
Il faut ensuite créer un projet de type DLL et implémenter les fonctions du fichier d'en-tête généré.
Le résultat de la compilation est une bibliothèque de fonctions qui doit être accessible depuis l'application Java. Sous Windows, il s'agit d'une Dynamically Linked Library (*.dll). Sous Linux, il s'agit d'un Shared Object (*.so).
Lien Java-Code natif
modifierLe lien est assuré par le code Java qui doit utiliser la méthode statique System.loadLibrary(String name)
.
Celle-ci a pour paramètre le nom de la bibliothèque de code natif à charger en mémoire.
La bibliothèque implémentant une méthode native doit impérativement être chargée avant l'appel à la méthode.
Elle doit être située dans l'un des chemins listés par la propriété java.library.path
.
Si la bibliothèque nommée n'est pas trouvée, une exception java.lang.UnsatisfiedLinkError est lancée.
Comme la bibliothèque doit être chargée avant toute utilisation de la classe, le chargement est généralement fait dans le bloc d'initialisation statique de la classe.
Portabilité
modifierLe nom de la bibliothèque fourni à la méthode statique System.loadLibrary(String name)
ne dépend pas du système d'exploitation car la JVM se charge de transformer le nom de bibliothèque en nom de fichier.
Pour une bibliothèque nommée test
, le fichier chargé par la JVM sera :
test.dll
sous Windows,libtest.so
sous Linux.
Pour qu'une application utilisant du code natif puisse s'exécuter sur différentes plateformes, il faut fournir une bibliothèque pour chacune d'entre elles.
Étapes
modifierLe développement d'application appelant du code natif se déroule en général de la façon suivante :
- Délimiter ce qui sera développé en Java, et en code natif (le minimum en général),
- Créer la classe Java déclarant les méthodes natives, et chargeant la bibliothèque native,
- La compiler,
- Générer le fichier d'en-tête (*.h) grâce à l'outil
javah
du JDK, - Créer un nouveau projet C ou C++ intégrant le fichier d'en-tête généré,
- Implémenter les méthodes du fichier d'en-tête,
- Compiler la bibliothèque, et la placer au bon endroit pour y accéder depuis Java,
- Tester et déboguer.