0Pricing
Java Academy · Leçon

Handles d’appels descendants

Appelez des fonctions natives

Handles d’appels descendants est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.

Appeler des fonctions natives

Un appel descendant est un appel effectué depuis Java vers du code natif. FFM représente chaque fonction native sous la forme d’un MethodHandle construit à partir d’un Linker.

Cette leçon vous guide pour rechercher, décrire et appeler une fonction C.

L’éditeur de liens natif

Linker.nativeLinker() renvoie l’éditeur de liens de la plateforme en cours d’exécution. Il connaît la convention d’appel C et peut produire des descripteurs pour les fonctions natives.

import java.lang.foreign.Linker;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        System.out.println("Got native linker: " + linker);
    }
}

Rechercher un symbole

Vous avez besoin de l’adresse de la fonction. linker.defaultLookup() recherche dans la bibliothèque C standard ; SymbolLookup.libraryLookup(name, arena) charge une bibliothèque partagée précise.

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        SymbolLookup stdlib = linker.defaultLookup();
        MemorySegment addr = stdlib.find("strlen").orElseThrow();
        System.out.println("strlen address found: " + addr);
    }
}

Décrire la signature

Un FunctionDescriptor décrit la signature C au moyen de dispositions. Pour size_t strlen(const char*), la valeur de retour est un entier long et l’argument est un pointeur (ADDRESS).

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        FunctionDescriptor desc = FunctionDescriptor.of(
            ValueLayout.JAVA_LONG,   // return: size_t
            ValueLayout.ADDRESS);    // arg: const char*
        System.out.println("Descriptor: " + desc);
    }
}

Construire le descripteur

Associez le symbole et la description avec downcallHandle pour obtenir un MethodHandle que vous pouvez appeler comme n’importe quelle méthode Java.

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

public class Main {
    public static void main(String[] args) {
        Linker linker = Linker.nativeLinker();
        MethodHandle strlen = linker.downcallHandle(
            linker.defaultLookup().find("strlen").orElseThrow(),
            FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
        System.out.println("Handle ready: " + strlen.type());
    }
}

Appeler la fonction

Pour appeler strlen, vous transmettez un pointeur vers une chaîne native. Allouez la chaîne dans une arène, puis appelez le descripteur avec invoke. Le résultat revient sous la forme d’un entier long Java.

import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

public class Main {
    public static void main(String[] args) throws Throwable {
        Linker linker = Linker.nativeLinker();
        MethodHandle strlen = linker.downcallHandle(
            linker.defaultLookup().find("strlen").orElseThrow(),
            FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
        try (Arena arena = Arena.ofConfined()) {
            MemorySegment str = arena.allocateUtf8String("Hello, FFM");
            long len = (long) strlen.invoke(str);
            System.out.println("Length = " + len);
        }
    }
}

Mapper les types

Chaque type C correspond à une disposition :

  • int vers ValueLayout.JAVA_INT
  • long/size_t vers JAVA_LONG
  • double vers JAVA_DOUBLE
  • n’importe quel pointeur vers ADDRESS

Il est essentiel de choisir les bonnes correspondances, sinon l’appel corrompt les données.

Fonctions renvoyant des pointeurs

Lorsqu’une fonction C renvoie un pointeur, le descripteur renvoie une MemorySegment de longueur nulle. Pour lire au-delà de son début, vous devez la réinterpréter à la taille correcte avec reinterpret(byteSize).

Transmettre plusieurs arguments

FunctionDescriptor.of(returnLayout, arg1, arg2, ...) énumère les arguments dans l’ordre. Pour une fonction void, utilisez FunctionDescriptor.ofVoid(args...) sans disposition de retour.

import java.lang.foreign.*;

public class Main {
    public static void main(String[] args) {
        // int (*)(const char*, int)
        FunctionDescriptor two = FunctionDescriptor.of(
            ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT);
        // void (*)(int)
        FunctionDescriptor noReturn = FunctionDescriptor.ofVoid(ValueLayout.JAVA_INT);
        System.out.println(two + " / " + noReturn);
    }
}

Gérer les erreurs avec throws

Comme MethodHandle.invoke déclare throws Throwable, votre méthode appelante doit gérer cette exception ou la déclarer. C’est pourquoi les exemples déclarent throws Throwable.

Mettre le descripteur en cache

Construire un descripteur d’appel est relativement coûteux ; faites-le donc une seule fois et réutilisez-le. Un modèle courant consiste à l’affecter à un champ static final lors de l’initialisation de la classe, puis à l’appeler de nombreuses fois.

Le descripteur lui-même peut être appelé simultanément par plusieurs fils d’exécution en toute sécurité.

Vérification rapide

Rappelez-vous comment décrire un argument pointeur C.

Récapitulatif

Vous avez appris à appeler des fonctions natives :

  • Linker.nativeLinker() associé à un SymbolLookup permet de rechercher des symboles
  • FunctionDescriptor décrit la signature avec des dispositions
  • downcallHandle produit un MethodHandle que vous pouvez appeler avec invoke
  • Les pointeurs correspondent à ADDRESS ; invoke provoque Throwable

Ensuite : décrire des données natives complexes avec des dispositions et des structures.

Questions Fréquemment Posées

La leçon « Handles d’appels descendants » est-elle gratuite ?

Oui — le texte complet de « Handles d’appels descendants » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Handles d’appels descendants » ?

Appelez des fonctions natives Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Java Academy ?

Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Handles d’appels descendants » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?

Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Pourquoi FFM plutôt que JNI
  2. MemorySegment et Arena
  3. Handles d’appels descendants
  4. Dispositions et structures
← Retour à Java Academy