0Pricing
Java Academy · บทเรียน

แฮนเดิลการเรียกลง

เรียกฟังก์ชันเนทีฟ

แฮนเดิลการเรียกลง เป็นบทเรียน 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_INT
  • long/size_t เป็น JAVA_LONG
  • double เป็น 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใดจึงเลือก FFM แทน JNI
  2. MemorySegment และ Arena
  3. แฮนเดิลการเรียกลง
  4. เลย์เอาต์และโครงสร้าง
← กลับไปที่ Java Academy