Article de reference

Interface native Java

( Apprenez comment et quand supprimer ce message ) L' interface Java Native Interface (ou Native Method Interface) est une interface de fonctions externes conçue pour les framew...

interface de fonctions externes conçue pour les frameworks de programmation non-Java . La JNI permet au code Java d'appeler et d'être appelé par du code natif (c'est-à-dire tout code utilisant l' interface binaire d'applicationJNIEnv C ), des applications natives (programmes spécifiques à une plateforme matérielle et un système d'exploitation ) et des bibliothèques écrites dans d'autres langages tels que C , C++ et assembleur .

Java 22 introduit l' API Foreign Function and Memory , qui peut être considérée comme la successeure de l'interface native Java.

bibliothèque de classes standard Java ne prend pas en charge certaines fonctionnalités spécifiques à la plateforme ou à une bibliothèque de programmes particulière. JNI est également utilisé pour modifier une application existante (écrite dans un autre langage de programmation) afin de la rendre accessible aux applications Java. De nombreuses classes de la bibliothèque standard dépendent de JNI pour fournir des fonctionnalités aux développeurs et aux utilisateurs, telles que les API d'entrée/sortie de fichiers et audio. Seules les applications et les applets signées peuvent invoquer JNI.

Le framework JNI permet au code natif de manipuler et d'utiliser des objets Java . Une méthode native (indiquée par le mot-clé `native` interface native Java AWT , disponible depuis J2SE 1.3.

JNI permet également un accès direct à l'assembleur , sans passer par un pont C. L'accès aux applications Java depuis l'assembleur est possible de la même manière.

L'interface JNI est le point d'entrée entre les langages utilisés pour démarrer la JVM.

Types de cartographie

Les types Java sont les types primitifs par défaut disponibles sur Java, tandis que les signatures de type JVM sont des identificateurs utilisés par la JVM pour identifier la correspondance de type sur Java, tandis que les types natifs sont des types définis par JNI lui-même pour correspondre à des types natifs. Pour les types primitifs, les typedefs suivants sont fournis :

Type Java typedef natif Description signature de type JVM Type natif le plus proche
booleanjboolean8 bits non signésZbool
bytejbytesigné 8 bitssignature de type JVM fait référence à la classe spécifiée de manière unique par ce nom ; par exemple, la signature ( dans les fichiers de classe ) fait référence à la classe . Le préfixe à la signature désigne un tableau de ce type ; par exemple, fait référence à , et fait référence à , jusqu’à un maximum de 255 dimensions.Lfully-qualified-class;Ljava.lang.String;Ljava/lang/String;conversion de type . Cependant, la correspondance entre les chaînes et les tableaux Java et les chaînes et tableaux natifs est différente ; par exemple, `int` jstringet char*`string` ne sont pas des types interchangeables, de même que `string` jintArrayet `string` int[].

JNI contient en outre les déclarations suivantes pour les types de référence Java dans <jni.h>:

Type Java Gestionnaire JNI
java.lang.Objectjobject
java.lang.Class(non générique)jclass
java.lang.Throwablejthrowable
java.lang.Stringjstring
T[](pour un type T)jarray
boolean[]jbooleanArray
byte[]jbyteArray
char[]jcharArray
short[]jshortArray
int[]jintArray
long[]jlongArray
float[]jfloatArray
double[]jdoubleArray
java.lang.Object[]jobjectArray

De plus, les types opaques suivants sont utilisés comme poignées :

méta-objet de classe Java Gestionnaire JNI
Champ de classejfieldID
Méthode de classejmethodID

Notez cependant que jfieldIDet jmethodIDne sont que des poignées opaques et ne correspondent pas à java.lang.reflect.Field/ java.lang.reflect.Method.

Conception

La communication entre le code natif et le code Java est assurée par le JNI, qui agit comme une ABI .

{JNIEXPORT void JNICALL Java_ClassName_MethodName ( JNIEnv * env , jobject obj , jstring javaString ) { const char * nativeString = env -> GetStringUTFChars ( javaString , 0 );// Effectuer une action sur la chaîne nativeenv -> ReleaseStringUTFChars ( javaString , nativeString ); }}

Le envpointeur est une structure qui contient l'interface avec la JVM. Il inclut toutes les fonctions nécessaires pour interagir avec la JVM et manipuler les objets Java. Tout ce que le code Java peut faire peut être fait avec ce pointeur JNIEnv. L'argument objest une référence à l'objet Java dans lequel cette méthode native a été déclarée.

Les types de données natifs peuvent être mappés vers/depuis les types de données Java. Pour les types composés, tels que les objets, les tableaux et les chaînes de caractères , le code natif doit explicitement convertir les données en appelant des méthodes dans le JNIEnv.

Un pointeur d'environnement JNI JNIEnv*est passé en argument à chaque fonction native mappée à une méthode Java, permettant ainsi l'interaction avec l'environnement JNI au sein de la méthode native. Ce pointeur d'interface JNI peut être stocké, mais reste valide uniquement dans le thread courant. Les autres threads doivent d'abord s'attacher AttachCurrentThread()à la JVM et obtenir un pointeur d'interface JNI. Une fois attaché, un thread natif fonctionne comme un thread Java classique exécuté dans une méthode native. Le thread natif reste attaché à la JVM jusqu'à ce qu'il appelle DetachCurrentThread()la méthode de détachement.

Le framework JNI ne fournit aucun système de nettoyage automatique de la mémoire pour les ressources mémoire non-JVM allouées par le code exécuté côté natif. Par conséquent, il incombe au code natif de libérer explicitement toutes les ressources acquises.

Sur les plateformes Linux et Solaris, si le code natif s'enregistre comme gestionnaire de signaux, il peut intercepter les signaux destinés à la JVM. Une chaîne de responsabilité permet l'interopérabilité entre le code natif et la JVM. Sur les plateformes Windows, la gestion structurée des exceptions (SEH) permet d'encapsuler le code natif dans des blocs SEH tryafin catchde capturer les interruptions logicielles générées par la machine (CPU/FPU), telles que les déréférencements de pointeurs nuls et les divisions par zéro, et de gérer ces situations avant que l'interruption ne soit propagée à la JVM (c'est-à-dire au code Java).

L' encodage pour NewStringUTF()les fonctions GetStringUTFLength()` get_to ...​​​​​​​​GetStringUTFChars()ReleaseStringUTFChars()GetStringUTFRegion()NewString()GetStringLength()GetStringChars()ReleaseStringChars()GetStringRegion()GetStringCritical()ReleaseStringCritical()" ); }

En Java, la fonction est alors appelée comme suit :

. System.loadLibrary ( " hello" ); // System.load() est une autre façon de charger une bibliothèque. }public natif void direHello ();public static void main ( String [] args ) { new HelloJNI (). sayHello (); } }

Performance

JNI encourt des frais généraux et une perte de performance considérables dans certaines circonstances :

  • Les appels de fonction aux méthodes JNI sont coûteux, surtout lorsqu'on appelle une méthode de manière répétée.
  • Les méthodes natives ne sont pas intégrées par la JVM, et la méthode ne peut pas non plus être compilée JIT , car elle est déjà compilée.
  • Un tableau Java peut être copié pour être utilisé dans le code natif, puis recopié ultérieurement. Le coût est linéaire par rapport à la taille du tableau.
  • Si la méthode reçoit un objet en paramètre ou doit effectuer un rappel, elle sera probablement amenée à interroger la JVM. L'accès aux champs, méthodes et types Java depuis du code natif fait appel à la réflexion Java . Les signatures sont spécifiées sous forme de chaînes de caractères et interrogées auprès de la JVM. Cette méthode est à la fois lente et sujette aux erreurs.
  • En Java, les chaînes de caractères sont des objets possédant une longueur et étant encodées. Accéder à une chaîne ou en créer une peut nécessiter une copie.

API de fonction étrangère et de mémoire

Java 22 a introduit l'API Foreign Functions and Memory (FFM), la gestion de la mémoire par régions . La classe `ForeignFunctions` java.lang.foreign.MemorySegmentmodélise un segment de mémoire contigu pouvant se trouver à l'intérieur ou à l'extérieur du tas JVM, et un ` ForeignFunctions` java.lang.foreign.MemorySegmentest alloué à l'aide d'un ` Remote` java.lang.foreign.Arenaqui contrôle la durée de vie de la région de mémoire sous-jacente à son segment alloué.

L' java.lang.foreign.Arenaoffre comprend les types d'arènes suivants :

Type d'arène Méthode d'usine Durée de vie limitée Fermeture explicite Accessible depuis plusieurs threads
MondialArena.global()NonNonOui
AutomatiqueArena.ofAuto()OuiNonOui
ConfinéArena.ofConfined()OuiOuiNon
CommunArena.ofShared()OuiOuiOui
à l' index % d : %d% n " , i , value ) ; } } } }

En un sens, l'API Java Foreign Function and Memory permet une allocation directe de mémoire en dehors du tas JVM (c'est-à-dire le tas du système d'exploitation), via Arena.allocate()et MemorySegment.allocateNative()qui allouent directement de la mémoire brute, tandis que Arena.close()et MemorySegment.close()sont utilisés pour désallouer/libérer le segment de mémoire.

En tant qu'interface de fonction étrangère , les classes java.lang.foreign.Linkersont proposées pour accéder aux fonctions étrangères de Java (vers et depuis), java.lang.foreign.SymbolLookuppour récupérer l'adresse d'un symbole dans une bibliothèque et java.lang.foreign.FunctionDescriptorpour modéliser la signature d'une fonction étrangère.

), FunctionDescriptor . of ( ValueLayout . JAVA_INT , ValueLayout . ADDRESS ) );MethodHandle strlen = linker . downcallHandle ( stdlib . findOrThrow ( "strlen" ), FunctionDescriptor . of ( ValueLayout . JAVA_LONG , ValueLayout . ADDRESS ) );try ( Arena arena = Arena.ofConfined ( )) { MemorySegment formatString = arena.allocateUtf8String ( " Hello , %s! " ) ; MemorySegment argString = arena.allocateUtf8String ( "World" ); printf.invokeExact ( formatString , argString ) ; // affiche " Hello , World !" long len = ( long ) strlen.invokeExact ( formatString ); // len = 5 } } }

Les mises en page sont modélisées par java.lang.foreign.ValueLayout, qui se compose de :

Taper Nom Description
java.lang.foreign.AddressLayoutADDRESSUne disposition d'adresse de même taille quesize_t
java.lang.foreign.AddressLayoutADDRESS_UNALIGEDUne disposition d'adresse non alignée de même taille quesize_t
java.lang.foreign.ValueLayout.OfBooleanJAVA_BOOLEANUne constante de mise en page de valeur de même taille qu'une valeur Javaboolean
java.lang.foreign.ValueLayout.OfByteJAVA_BYTEUne constante de mise en page de valeur de même taille qu'une valeur Javabyte
java.lang.foreign.ValueLayout.OfCharJAVA_CHARUne constante de mise en page de valeur de même taille qu'une valeur Javachar
java.lang.foreign.ValueLayout.OfCharJAVA_CHAR_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javachar
java.lang.foreign.ValueLayout.OfShortJAVA_SHORTUne constante de mise en page de valeur de même taille qu'une valeur Javashort
java.lang.foreign.ValueLayout.OfShortJAVA_SHORT_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javashort
java.lang.foreign.ValueLayout.OfIntJAVA_INTUne constante de mise en page de valeur de même taille qu'une valeur Javaint
java.lang.foreign.ValueLayout.OfIntJAVA_INT_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javaint
java.lang.foreign.ValueLayout.OfLongJAVA_LONGUne constante de mise en page de valeur de même taille qu'une valeur Javalong
java.lang.foreign.ValueLayout.OfLongJAVA_LONG_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javalong
java.lang.foreign.ValueLayout.OfFloatJAVA_FLOATUne constante de mise en page de valeur de même taille qu'une valeur Javafloat
java.lang.foreign.ValueLayout.OfFloatJAVA_FLOAT_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javafloat
java.lang.foreign.ValueLayout.OfDoubleJAVA_DOUBLEUne constante de mise en page de valeur de même taille qu'une valeur Javadouble
java.lang.foreign.ValueLayout.OfDoubleJAVA_DOUBLE_UNALIGNEDUne mise en page de valeurs non alignées de même taille qu'une Javadouble

Les types primitifs reçoivent ValueLayout.JAVA_*des mises en page lorsqu'ils sont mappés à leurs types natifs, tandis que les types pointeurs utilisent ValueLayout.ADDRESS(par exemple char*, int**ou struct Point*).

De plus, la constante MemorySegment.NULL(de type java.lang.foreign.MemorySegment) est un segment natif de longueur nulle représentant une adresse nulle ( nullptr), équivalent à MemorySegment.ofAddress(0).

Java offre des méthodes supplémentaires pour exprimer des types natifs plus complexes. Par exemple, les types natifs suivants

),MemoryLayout.paddingLayout(4),ValueLayout.JAVA_LONG.withName("y")};UnionLayoutchoiceLayout=MemoryLayout.unionLayout(ValueLayout.JAVA_FLOAT.withName("a"),ValueLayout.JAVA_INT.withName("b"));

Alternatives

The Java Runtime Interface was created by Netscape as a precursor.

Microsoft's proprietary implementation of a Java Virtual Machine (Visual J++) had a similar mechanism for calling native code from Java, called the Raw Native Interface (RNI). In addition, it offered a simple way to call existing native code that was not itself aware of Java, such as (but not limited to) the Windows API, (J/Direct). However, following the Sun–Microsoft litigation about this implementation, Visual J++ ceased to be maintained. RNI was simpler to use than JNI, because no management of the Java environment pointer was needed; instead, all Java objects were accessed directly. To facilitate this, a tool was used to generate header files from Java classes. Similarly, J/Direct was easier to use than using the necessary intermediate native library and JNI.

Java Native Access (JNA) is a community-developed library that provides Java programmers easy access to native shared libraries without using JNI. However, this requires the redistribution of the dependent jar library. The tradeoff is between JNI being more complex and JNA being slower, and not built-in like JNI.

Historically, GCC (until GCC 7) offered the GNU Compiler for Java. This compiler offered the Compiled Native Interface (CNI), which allowed direct interoperability between C++ and Java. It provided an API that was heavily based off of JNI itself. It claimed several advantages over JNI, as it represented Java classes directly as C++ classes.

Depuis Java 22, l'API Foreign Function and Memory remplace JNI, en raison de sa réduction du code répétitif et de son interface simplifiée.

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index