从 Java 调用 C 代码

首页

/

Language

/

从 Java 调用 C 代码

Language

高级

从 Java 调用 C 代码

贡献

🐛 报告代码问题

🌐 报告翻译问题

💡 建议新模式

FFM 让 Java 直接调用 C 库,无需 JNI 样板代码或在 C 端了解 Java。

Foreign Function & Memory API

Native Code

代码对比

✕ Java 1.1+

复制

public class CallCFromJava {

static { System.loadLibrary("strlen-jni"); }

public static native long strlen(String s);

public static void main(String[] args) {

long ret = strlen("Bambi");

System.out.println("Return value " + ret); // 5

}

}

// Run javac -h to generate the .h file, then write C:

// #include "CallCFromJava.h"

// #include

// JNIEXPORT jlong JNICALL Java_CallCFromJava_strlen(

// JNIEnv *env, jclass clazz, jstring str) {

// const char* s = (*env)->GetStringUTFChars(env, str, NULL);

// jlong len = (jlong) strlen(s);

// (*env)->ReleaseStringUTFChars(env, str, s);

// return len;

// }

✓ Java 22+

复制

void main() throws Throwable {

try (var arena = Arena.ofConfined()) {

// Use any system library directly — no C wrapper needed

var stdlib = Linker.nativeLinker().defaultLookup();

var foreignFuncAddr = stdlib.find("strlen").orElseThrow();

var strlenSig = FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);

var strlenMethod = Linker.nativeLinker() .downcallHandle(foreignFuncAddr, strlenSig);

var ret = (long) strlenMethod.invokeExact(arena.allocateFrom("Bambi"));

System.out.println("Return value " + ret); // 5

}

}

// Your own C library needs no special Java annotations:

// long greet(char* name) {

// printf("Hello %s\n", name);

// return 0;

// }

分享

𝕏

🦋

in

发现此代码有问题? 告诉我们。

为什么现代方式更好

👁

C 代码保持纯 C

C 函数无需 JNI 注解或 JNIEnv 样板——任何现有的 C 库都可以直接调用。

更灵活

无需编写适配器代码或生成头文件,即可直接调用大多数现有的 C/C++ 库。

🛠️

工作流更简便

无需停下来运行 javac -h,也无需实现生成的 .h 文件中定义的接口。

旧方式

JNI(Java 原生接口)

现代方式

FFM(外部函数与内存 API)

自 JDK

22

难度

高级

JDK 支持

从 Java 调用 C 代码

可用

在 JDK 22 中标准化(2024 年 3 月);此前自 JDK 14 起处于孵化阶段

工作原理

Java 有两种调用原生 C/C++ 代码的方式:传统的 JNI 和现代的 FFM API。使用 JNI,需要将方法声明为 native,运行 javac -h 生成 C 头文件,然后使用繁琐的 JNI C API(JNIEnv、jstring 等)实现函数。FFM 在 Java 22 中作为标准 API 引入,消除了这一切:C 代码就是普通的 C——无需 JNI 约定。这使得调用现有 C/C++ 库无需修改变得更加容易。Java 端使用 Arena 进行安全的堆外内存管理,使用 MethodHandle 进行降调用,确保灵活性和安全性。

相关文档

JEP 454: Foreign Function & Memory API ↗

java.lang.foreign package (Java 22) ↗

证明

查看证明源码 ↗

相关模式

I/O

高级

File memory mapping

Java 8

try (FileChannel channel =

FileChannel.open(path,

StandardOpenOption.READ,

StandardOpenOption.WRITE)) {

MappedByteBuffer buffer =

channel.map(

FileChannel.MapMode.READ_WRITE,

0, (int) channel.size());

// Limited to 2GB

// Freed by GC, no control

}

Java 22+

FileChannel channel =

FileChannel.open(path,

StandardOpenOption.READ,

StandardOpenOption.WRITE);

try (Arena arena = Arena.ofShared()) {

MemorySegment segment =

channel.map(

FileChannel.MapMode.READ_WRITE,

0, channel.size(), arena);

// No size limit

// ...

} // Deterministic cleanup

悬停查看现代版 ➜

JDK 22+

Language

入门

Compact source files

Java 8

public class HelloWorld {

public static void main(String[] args) {

System.out.println(

"Hello, World!");

}

}

Java 25

void main() {

IO.println("Hello, World!");

}

悬停查看现代版 ➜

JDK 25+

Language

入门

Unnamed variables with _

Java 8

try {

parse(input);

} catch (Exception ignored) {

log("parse failed");

}

map.forEach((key, value) -> {

process(value); // key unused

});

Java 22+

try {

parse(input);

} catch (Exception _) {

log("parse failed");

}

map.forEach((_, value) -> {

process(value);

});

悬停查看现代版 ➜

JDK 22+

Copyright © 2088 斗念英雄·卡牌对战活动专区 All Rights Reserved.
友情链接