You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JEP 412外部函数与内存API在Java 17中调用C函数

Java 17 调用C函数极简完整示例(基于JEP 412 Foreign Function & Memory API,无第三方工具)

前置条件

  • 已安装JDK 17及以上版本,配置好JAVA_HOME环境变量
  • 已安装C编译工具链(GCC/Clang/VS Build Tools均可)
  • 注意:Java 17中FFM API是孵化器特性,运行时需加额外参数

第一步:创建并编译C动态库

1.1 编写C代码

新建mymath.c文件,内容如下:

// 简单的加法函数,供Java调用
int add(int a, int b) {
    return a + b;
}

1.2 编译为动态链接库

根据操作系统执行对应编译命令:

  • Linux/macOS(生成libmymath.so/libmymath.dylib):
    # Linux
    gcc -shared -fPIC -o libmymath.so mymath.c
    # macOS
    gcc -shared -fPIC -o libmymath.dylib mymath.c
    
  • Windows(生成mymath.dll):
    cl /LD mymath.c /Fe:mymath.dll
    

编译完成后把生成的动态库文件放到Java项目的根目录即可。


第二步:编写Java调用代码

2.1 核心流程说明

全程只使用JDK内置API,无需任何额外工具:

  1. 获取系统原生链接器
  2. 加载编译好的C动态库
  3. 查找目标C函数的符号
  4. 定义函数的入参、出参类型描述符,生成MethodHandle
  5. 调用MethodHandle执行C函数

2.2 完整Java代码

新建FFMDemo.java:

import jdk.incubator.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;

public class FFMDemo {
    public static void main(String[] args) throws Throwable {
        // 1. 获取系统原生链接器
        Linker linker = Linker.nativeLinker();
        // 2. 加载动态库,获取符号查找器
        SymbolLookup lookup = SymbolLookup.loaderLookup();

        // 3. 查找add函数的符号
        MemorySegment addFunc = lookup.lookup("add")
                .orElseThrow(() -> new RuntimeException("找不到add函数,请检查动态库是否正确放置"));

        // 4. 构造函数描述符:返回值int,两个入参都是int,生成MethodHandle
        MethodHandle addHandle = linker.downcallHandle(
                addFunc,
                MethodType.methodType(int.class, int.class, int.class),
                FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT)
        );

        // 5. 调用C函数
        int result = (int) addHandle.invokeExact(10, 20);
        System.out.println("C函数add(10,20)的返回结果:" + result);
    }
}

第三步:编译运行Java代码

因为FFM API在Java17中是孵化器特性,编译和运行都需要加额外参数:

3.1 编译代码

javac --add-modules jdk.incubator.foreign FFMDemo.java

3.2 运行代码

  • Linux/macOS:
    java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED FFMDemo
    
  • Windows:
    注意把动态库所在目录加到PATH环境变量,或者运行时指定java.library.path:
    java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED -Djava.library.path=. FFMDemo
    

预期输出

C函数add(10,20)的返回结果:30

常见问题排查

  • 提示找不到函数符号:检查C函数是否加了static修饰(加了就不会对外暴露符号),动态库命名是否符合系统规范(Linux要lib前缀.so后缀,Windows直接.dll后缀)
  • 提示孵化器模块错误:确认JDK版本是17及以上,编译运行参数都加了--add-modules jdk.incubator.foreign
  • 提示没有本地访问权限:运行参数加--enable-native-access=ALL-UNNAMED,如果是模块化项目把ALL-UNNAMED换成你的模块名即可

内容的提问来源于stack exchange,提问作者Yogesh Chaudhari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 00:54:04