Uchwyty downcall
Wywoływanie funkcji natywnych
Uchwyty downcall to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Wywoływanie funkcji natywnych
Downcall to wywołanie z Javy do kodu natywnego. FFM reprezentuje każdą funkcję natywną jako obiekt MethodHandle utworzony na podstawie obiektu Linker.
W tej lekcji omówiono wyszukiwanie, opisywanie i wywoływanie funkcji C.
Linker natywny
Linker.nativeLinker() zwraca linker dla uruchomionej platformy. Zna on konwencję wywoływania C i potrafi tworzyć uchwyty do funkcji natywnych.
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);
}
}Wyszukiwanie symbolu
Potrzebny jest adres funkcji. linker.defaultLookup() przeszukuje standardową bibliotekę C, a SymbolLookup.libraryLookup(name, arena) ładuje konkretną bibliotekę współdzieloną.
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);
}
}Opisywanie sygnatury
Obiekt FunctionDescriptor opisuje sygnaturę C za pomocą layoutów. Dla size_t strlen(const char*) wartością zwracaną jest long, a argumentem wskaźnik (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);
}
}Budowanie uchwytu
Połącz symbol i deskryptor za pomocą downcallHandle, aby otrzymać obiekt MethodHandle, który można wywoływać tak jak każdą metodę Javy.
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());
}
}Wywoływanie funkcji
Aby wywołać strlen, należy przekazać wskaźnik do napisu natywnego. Napis należy przydzielić w obiekcie arena, a następnie wywołać uchwyt za pomocą invoke. Wynik zostanie zwrócony jako wartość typu long w Javie.
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);
}
}
}Mapowanie typów
Każdy typ C jest odwzorowywany na layout:
intnaValueLayout.JAVA_INTlong/size_tnaJAVA_LONGdoublenaJAVA_DOUBLE- dowolny wskaźnik na
ADDRESS
Poprawne mapowanie ma kluczowe znaczenie, ponieważ błąd powoduje uszkodzenie danych przez wywołanie.
Funkcje zwracające wskaźniki
Gdy funkcja C zwraca wskaźnik, uchwyt zwraca obiekt MemorySegment o zerowej długości. Aby odczytać dane poza jego początkiem, trzeba wykonać operację reinterpretacji do właściwego rozmiaru za pomocą reinterpret(byteSize).
Przekazywanie wielu argumentów
FunctionDescriptor.of(returnLayout, arg1, arg2, ...) wymienia argumenty w kolejności ich przekazywania. W przypadku funkcji void należy użyć FunctionDescriptor.ofVoid(args...), bez layoutu wartości zwracanej.
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);
}
}Obsługa błędów za pomocą throws
Ponieważ MethodHandle.invoke deklaruje throws Throwable, metoda wywołująca musi obsłużyć ten wyjątek lub zadeklarować jego propagowanie. Dlatego przykłady deklarują throws Throwable.
Buforowanie uchwytu
Budowanie uchwytu downcall jest stosunkowo kosztowne, dlatego należy wykonać je raz i ponownie używać uchwytu. Typowym wzorcem jest przypisanie uchwytu do pola static final podczas inicjalizacji klasy, a następnie wielokrotne jego wywoływanie.
Sam uchwyt jest bezpieczny w przypadku równoczesnych wywołań z wielu wątków.
Szybkie sprawdzenie
Proszę przypomnieć sobie, jak opisuje się argument będący wskaźnikiem C.
Podsumowanie
Dowiedzieli się Państwo, jak wywoływać funkcje natywne:
Linker.nativeLinker()wraz z obiektemSymbolLookupsłuży do wyszukiwania symboliFunctionDescriptoropisuje sygnaturę za pomocą layoutówdowncallHandlezwraca obiektMethodHandle, który można wywołać za pomocąinvoke- Wskaźniki są mapowane na
ADDRESS, ainvokezgłaszaThrowable
Następnie: opisywanie złożonych danych natywnych za pomocą layoutów i struktur.
Często zadawane pytania
Czy lekcja „Uchwyty downcall” jest bezpłatna?
Tak — pełny tekst „Uchwyty downcall” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Uchwyty downcall”?
Wywoływanie funkcji natywnych Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Uchwyty downcall”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.