发布于2026-07-07 阅读(0)
扫一扫,手机访问
先写一个简单的C函数,编译成动态库,后面所有调用都基于它。
#includeint test(char *input){ printf("input:%s\n",input); return 0; }
编译命令如下,生成libtest.so:
[root@node-126 ~]# gcc -fPIC -shared -o libtest.so test.c [root@node-126 ~]# ls /root/ anaconda-ks.cfg libtest.so node-v6.10.2-linux-x64.tar.xz original-ks.cfg spring3 test test.c
用nm -D查看符号表,确认test方法已导出:
[root@node-126 ~]# nm -D libtest.so
0000000000201038 B __bss_start
w __cxa_finalize
0000000000201038 D _edata
0000000000201040 B _end
0000000000000600 T _fini
w __gmon_start__
00000000000004c0 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U printf
00000000000005d5 T test
新建一个普通Ma ven项目,引入JNA依赖:
net.ja va.dev.jna jna 5.5.0
定义接口继承Library,并加载动态库:
package jna;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface MyClibrary extends Library {
MyClibrary INSTANTCE = Native.load("/root/libtest.so", MyClibrary.class);
int test(String input);
}
测试代码:
import jna.MyClibrary;
public class Main {
public static void main(String[] args) {
int test = MyClibrary.INSTANTCE.test("extend Library");
System.out.println(test);
}
}
在Linux上运行Ja va程序,结果如下:

另一种方式不用定义接口,直接用NativeLibrary获取函数对象:
import com.sun.jna.Function;
import com.sun.jna.NativeLibrary;
public class Main {
public static void main(String[] args) {
NativeLibrary instance = NativeLibrary.getInstance("/root/libtest.so");
Function func = instance.getFunction("test");
Object res = func.invoke(Integer.class, new Object[]{"NativeLibrary.getInstance"});
System.out.println( res);
}
}
如果希望用传统的JNI方式暴露本地方法,但又想保留JNA的灵活性,可以这样做。首先创建Ja va类声明native方法:
// 文件路径 /root/jna/MyNative.ja va
package jna;
import ja va.io.IOException;
public class MyNative {
native int test(String input) throws IOException;
}
编译并生成JNI头文件(注意JDK版本要一致,这里以JDK8为例):
/usr/local/jdk1.8.0_111/bin/ja vac MyNative.ja va /usr/local/jdk1.8.0_111/bin/ja vah -classpath /root/ -jni jna.MyNative
然后实现头文件中的接口。可以直接在Linux上编辑C源文件:
#include#include #include "jna_MyNative.h" jint Ja va_jna_MyNative_test(JNIEnv *jniEnv, jobject clazz, jstring input){ printf("input:%s\n",(char *)input); return 0; }
编译时注意引入JDK头文件路径:
gcc -fPIC -shared -I/usr/lib/jvm/jdk-17-oracle-x64/include -I/usr/lib/jvm/jdk-17-oracle-x64/include/linux -o libtest.so test.c
也可以使用Clion开发环境,新建C项目,引入头文件并实现方法:

几点注意事项:
include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include")同步失败,本地找不到符号,但实际可以正常运行。jniEnv指针必须由Ja va调用时才会被正确赋值。CMake配置示例:
cmake_minimum_required(VERSION 2.8) project(untitled1) set(CMAKE_CXX_STANDARD 17) include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include") include_directories(SYSTEM "/usr/lib/jvm/jdk-17-oracle-x64/include/linux") add_executable(testexe main.cpp) add_library(test SHARED main.cpp jna_MyNative.h) target_link_libraries(test -I/usr/lib/jvm/jdk-17-oracle-x64/include -I/usr/lib/jvm/jdk-17-oracle-x64/linux) install(TARGETS test LIBRARY DESTINATION /usr/lib)
Ja va侧调用测试:
import jna.MyNative;
import ja va.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
System.load("/root/jna/libtest.so");
//System.loadLibrary("test"); // 自动拼接成libtest.so,默认从/usr/lib,/usr/lib64等路径找
MyNative myNative = new MyNative();
int test = myNative.test("native");
System.out.println(test);
}
}
虽然方式3是以JNI风格实现的,但生成的libtest.so依然可以被前两种JNA方式调用,只是函数名变成了Ja va_jna_MyNative_test:
[root@node-126 lib]# nm -D /usr/lib/libtest.so 0000000000201070 B __bss_start ... 0000000000000a15 T Ja va_jna_MyNative_test ...
以上是JNA调用C接口的三种常见做法:继承Library接口、直接操作NativeLibrary、以及结合JNI声明native方法。每种方式各有适用场景,开发者可以根据实际项目需求灵活选择。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8