แฮนเดิลการเรียกลง
เรียกฟังก์ชันเนทีฟ
แฮนเดิลการเรียกลง เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
การเรียกใช้ฟังก์ชันเนทีฟ
การเรียกลง คือการเรียกจาก Java ลงไปยังโค้ดเนทีฟ FFM แทนฟังก์ชันเนทีฟแต่ละฟังก์ชันด้วย MethodHandle ที่สร้างจาก Linker
บทเรียนนี้จะแนะนำการค้นหา การอธิบาย และการเรียกใช้ฟังก์ชันภาษาซี
ตัวเชื่อมโยงเนทีฟ
Linker.nativeLinker() ส่งคืนตัวเชื่อมโยงสำหรับแพลตฟอร์มที่กำลังทำงานอยู่ ตัวเชื่อมโยงนี้ทราบรูปแบบการเรียกใช้ของภาษาซี และสามารถสร้างตัวจัดการสำหรับฟังก์ชันเนทีฟได้
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);
}
}การค้นหาสัญลักษณ์
คุณต้องใช้ที่อยู่ของฟังก์ชัน linker.defaultLookup() จะค้นหาในไลบรารีภาษาซีมาตรฐาน ส่วน SymbolLookup.libraryLookup(name, arena) จะโหลดไลบรารีที่ใช้ร่วมกันตามที่ระบุ
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);
}
}การอธิบายลายเซ็น
FunctionDescriptor อธิบายลายเซ็นของภาษาซีในรูปของเลย์เอาต์ สำหรับ size_t strlen(const char*) ค่าส่งกลับเป็นจำนวนเต็มขนาดยาว และอาร์กิวเมนต์เป็นตัวชี้ (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);
}
}การสร้างตัวจัดการ
รวมสัญลักษณ์และตัวบอกลักษณะเข้าด้วยกันด้วย downcallHandle เพื่อรับ MethodHandle ที่คุณเรียกใช้ได้เหมือนเมธอด 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());
}
}การเรียกใช้ฟังก์ชัน
หากต้องการเรียก strlen คุณต้องส่งตัวชี้ไปยังสตริงเนทีฟ จัดสรรสตริงในอารีนา แล้วใช้ invoke กับตัวจัดการ ผลลัพธ์จะถูกส่งกลับมาเป็นค่า 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);
}
}
}การจับคู่ชนิดข้อมูล
ชนิดข้อมูลแต่ละชนิดของภาษาซีจะจับคู่กับเลย์เอาต์ดังนี้:
intเป็นValueLayout.JAVA_INTlong/size_tเป็นJAVA_LONGdoubleเป็นJAVA_DOUBLE- ตัวชี้ใด ๆ เป็น
ADDRESS
การจับคู่ให้ถูกต้องเป็นสิ่งสำคัญอย่างยิ่ง มิฉะนั้นการเรียกใช้จะทำให้ข้อมูลเสียหาย
ฟังก์ชันที่ส่งคืนตัวชี้
เมื่อฟังก์ชันภาษาซีส่งคืนตัวชี้ ตัวจัดการจะส่งคืน MemorySegment ที่มีความยาวเป็นศูนย์ หากต้องการอ่านเลยจุดเริ่มต้น คุณต้อง ตีความใหม่ ให้มีขนาดถูกต้องด้วย reinterpret(byteSize)
การส่งอาร์กิวเมนต์หลายรายการ
FunctionDescriptor.of(returnLayout, arg1, arg2, ...) แสดงรายการอาร์กิวเมนต์ตามลำดับ หากเป็นฟังก์ชันที่ไม่ส่งคืนค่า ให้ใช้ FunctionDescriptor.ofVoid(args...) โดยไม่ต้องระบุเลย์เอาต์ค่าส่งกลับ
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);
}
}จัดการข้อผิดพลาดด้วยการประกาศโยนข้อผิดพลาด
เนื่องจาก MethodHandle.invoke ประกาศว่าอาจ throws Throwable เมธอดที่เรียกใช้จึงต้องจัดการหรือประกาศข้อผิดพลาดดังกล่าว นี่คือเหตุผลที่ตัวอย่างประกาศ throws Throwable
การแคชตัวจัดการ
การสร้างตัวจัดการการเรียกลงมีต้นทุนค่อนข้างสูง จึงควรทำเพียง ครั้งเดียว แล้วนำกลับมาใช้ซ้ำ รูปแบบที่ใช้กันทั่วไปคือผูกตัวจัดการไว้ในฟิลด์ค่าคงที่ระดับคลาสระหว่างการเริ่มต้นคลาส แล้วเรียกใช้หลายครั้ง
ตัวจัดการเองปลอดภัยต่อการเรียกพร้อมกันจากหลายเธรด
ตรวจสอบอย่างรวดเร็ว
ทบทวนวิธีอธิบายอาร์กิวเมนต์ตัวชี้ของภาษาซี
สรุปทบทวน
คุณได้เรียนรู้การเรียกใช้ฟังก์ชันเนทีฟ:
Linker.nativeLinker()ร่วมกับSymbolLookupเพื่อค้นหาสัญลักษณ์FunctionDescriptorอธิบายลายเซ็นด้วยเลย์เอาต์downcallHandleให้ผลเป็นMethodHandleที่คุณใช้invokeได้- ตัวชี้จับคู่กับ
ADDRESSและinvokeอาจส่งThrowable
ถัดไป: การอธิบายข้อมูลเนทีฟที่ซับซ้อนด้วยเลย์เอาต์และโครงสร้างข้อมูล
คำถามที่พบบ่อย
บทเรียน “แฮนเดิลการเรียกลง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “แฮนเดิลการเรียกลง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “แฮนเดิลการเรียกลง”
เรียกฟังก์ชันเนทีฟ คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “แฮนเดิลการเรียกลง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ