JNI调用本地代码获取控制台尺寸时遇UnsatisfiedLinkError求助
解决JNI调用控制台宽高时的java.lang.UnsatisfiedLinkError异常
我之前也碰到过一模一样的问题,这种JNI链接错误90%以上都是本地库加载不对、方法签名不匹配或者编译架构不兼容导致的,咱们一步步来排查解决:
1. 先确认本地库是否正确加载
首先要确保你的Java代码里已经正确加载了编译好的本地库(Windows下是.dll,Linux/macOS下是.so/.dylib):
- 推荐在
NativeConsole类的静态代码块里加载,比如:package project.console; public class NativeConsole { static { // 注意:这里的库名要去掉前缀后缀,比如你的库是libconsole.dll,就写"console" System.loadLibrary("console"); // 或者用绝对路径加载:System.load("C:/your/path/libconsole.dll"); } public native static int getConsoleWidth(); } - 运行Java程序时,要确保JVM能找到这个库:要么把库放到系统默认的库路径里,要么用
-Djava.library.path参数指定库所在目录,比如:java -cp your-class-path -Djava.library.path=/path/to/your/libs project.Core
2. 检查JNI方法签名是否完全匹配
这是最容易踩的坑!JNI方法的签名必须和Java类的全限定名、方法名、参数/返回值完全对应:
- 不要手动写JNI方法名,建议用JDK自带的
javah命令自动生成头文件:- 先编译你的Java类,得到
project/console/NativeConsole.class文件 - 进入到class文件的根目录(比如
target/classes),执行命令:javah project.console.NativeConsole - 生成的头文件里会有正确的方法签名,比如:
JNIEXPORT jint JNICALL Java_project_console_NativeConsole_getConsoleWidth (JNIEnv *, jclass);
- 先编译你的Java类,得到
- 你的C/C++实现必须严格按照这个头文件的方法名来写,差一个下划线或者大小写都不行!
3. 确认本地库的编译是否正确
编译本地代码时要注意几个关键点:
- 必须链接对应JDK版本的JNI头文件,编译命令里要包含JDK的
include和include/[系统目录]路径,比如Windows下用MSVC编译:
Linux下用gcc编译:cl /I "C:\Program Files\Java\jdk1.8.0_301\include" /I "C:\Program Files\Java\jdk1.8.0_301\include\win32" /LD console.c /Fe:libconsole.dllgcc -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux -shared -fPIC console.c -o libconsole.so - 编译架构必须和JVM一致:如果你的JVM是64位,本地库也必须编译成64位;32位JVM只能用32位的库,否则会出现链接错误。
4. 完整示例代码参考
给你一套能直接跑的示例,对照着检查你的代码:
Java类(project/console/NativeConsole.java)
package project.console; public class NativeConsole { static { System.loadLibrary("console"); } public native static int getConsoleWidth(); public native static int getConsoleHeight(); }
C实现代码(console.c)
#include <jni.h> #include "project_console_NativeConsole.h" #ifdef _WIN32 #include <windows.h> #else #include <sys/ioctl.h> #include <unistd.h> #endif JNIEXPORT jint JNICALL Java_project_console_NativeConsole_getConsoleWidth (JNIEnv *env, jclass cls) { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.srWindow.Right - csbi.srWindow.Left + 1; #else struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_col; #endif } JNIEXPORT jint JNICALL Java_project_console_NativeConsole_getConsoleHeight (JNIEnv *env, jclass cls) { #ifdef _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #else struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); return w.ws_row; #endif }
最后排查小技巧
如果还是不行,可以用工具辅助排查:
- Windows下用Dependency Walker打开你的
.dll,看看有没有缺失的依赖库; - Linux下用
ldd libconsole.so命令检查依赖; - 运行Java程序时加上
-verbose:jni参数,会输出JNI加载的详细日志,能帮你定位问题。
内容的提问来源于stack exchange,提问作者Human
相关产品推荐
相关产品推荐

