Handle per downcall
Chiamare funzioni native
Handle per downcall è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.
Chiamare funzioni native
Una downcall è una chiamata da Java al codice nativo. FFM rappresenta ogni funzione nativa come un MethodHandle costruito a partire da un Linker.
Questa lezione illustra come individuare, descrivere e invocare una funzione C.
Il linker nativo
Linker.nativeLinker() restituisce il linker per la piattaforma in esecuzione. Conosce la convenzione di chiamata C e può creare handle per le funzioni native.
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);
}
}Individuazione di un simbolo
È necessario l'indirizzo della funzione. linker.defaultLookup() cerca nella libreria C standard; SymbolLookup.libraryLookup(name, arena) carica una libreria condivisa specifica.
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);
}
}Descrizione della firma
Un FunctionDescriptor descrive la firma C in termini di layout. Per size_t strlen(const char*), il valore restituito è un long e l'argomento è un puntatore (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);
}
}Creazione dell'handle
Si combinano il simbolo e il descrittore con downcallHandle per ottenere un MethodHandle che si può invocare come un qualsiasi metodo 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());
}
}Invocazione della funzione
Per chiamare strlen si passa un puntatore a una stringa nativa. Allochi la stringa in un'arena, quindi invochi l'handle con invoke. Il risultato viene restituito come 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);
}
}
}Mappatura dei tipi
A ogni tipo C corrisponde un layout:
intcorrisponde aValueLayout.JAVA_INTlong/size_tcorrisponde aJAVA_LONGdoublecorrisponde aJAVA_DOUBLE- qualsiasi puntatore corrisponde a
ADDRESS
Queste corrispondenze devono essere corrette, altrimenti la chiamata corrompe i dati.
Funzioni che restituiscono puntatori
Quando una funzione C restituisce un puntatore, l'handle restituisce un MemorySegment di lunghezza zero. Per leggere oltre l'inizio, è necessario reinterpretarlo con la dimensione corretta usando reinterpret(byteSize).
Passaggio di molti argomenti
FunctionDescriptor.of(returnLayout, arg1, arg2, ...) elenca gli argomenti nell'ordine. Per una funzione void si usa FunctionDescriptor.ofVoid(args...) senza un layout del valore restituito.
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);
}
}Gestire gli errori con throws
Poiché MethodHandle.invoke dichiara throws Throwable, il metodo chiamante deve gestire l'errore o dichiararlo. Ecco perché gli esempi dichiarano throws Throwable.
Memorizzazione nella cache dell'handle
La creazione di un handle di downcall è relativamente costosa, quindi la esegua una sola volta e lo riutilizzi. Un modello comune consiste nell'associare l'handle a un campo static final durante l'inizializzazione della classe e invocarlo molte volte.
L'handle è thread-safe e può essere chiamato simultaneamente da più thread.
Verifica rapida
Ricordi come si descrive un argomento puntatore C.
Riepilogo
Ha appreso a chiamare funzioni native:
Linker.nativeLinker()insieme a unSymbolLookupper trovare i simboliFunctionDescriptordescrive la firma tramite i layoutdowncallHandlerestituisce unMethodHandleche si puòinvoke- I puntatori corrispondono a
ADDRESS;invokepuò lanciareThrowable
Prossimo argomento: descrivere dati nativi complessi con layout e struct.
Domande Frequenti
La lezione «Handle per downcall» è gratuita?
Sì — il testo completo di «Handle per downcall» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.
Cosa imparerò in «Handle per downcall»?
Chiamare funzioni native Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Java Academy?
Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Handle per downcall»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Java Academy?
Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Perché FFM invece di JNI
- MemorySegment e Arena
- Handle per downcall
- Layout e struct