jni使用
最近做的项目需要调用本地C++代码,正好在Java中可以通过JNI机制来支持内地代码的使用。
下面记录下使用方式
在使用之前我们首先得具备java和c++的开发能力,没有也没关系。我就只会写java,动态库让c++的同学提供就好。
在不同的平台下,本地动态库的格式是不一样的:
- windows -> .dll
- 类UNIX平台- > .so
首先创建一个java类
package com.jni.demo;
public class NativeLibraryDemo {
private static native String fun1(String data);
private static native String fun2(String data, String ip);
}
# 生成头文件
在jdk8后使用如下命令
javac -h . NativeLibraryDemo.java
1.8之前自行查找吧,都java20了,该换了。
头文件内容如下:
将java的native方法转换成C函数声明的规则是这样的:Java_{package_and_classname}_{function_name}(JNI arguments)。包名中的点换成单下划线。
会发现多个几个参数:
- JNIEnv *:这是一个指向JNI运行环境的指针,后面我们会看到,我们通过这个指针访问JNI函数
- jobject:这里指代java中的this对象
后面的话就可以交给C++的同学了。
当你拿到了他给你的 dll/so 文件后,要在java程序中加载这个文件。
下面记录两种方式:
# 加载动态库路径
在jvm启动参数中制定动态库路径:
-Djava.library.path={具体放置动态库文件夹路径}
在NativeLibraryDemo
静态代码块加入如下代码
static {
final String LIBRARY_NAME = "demo";
System.loadLibrary(LIBRARY_NAME);
}
如果你不去配置启动参数,在程序中使用如下代码
System.setProperty("java.library.path");
当然是不行的。原因是java.library.path
这个路径在程序启动时就被ClassLoader加载了。
可以通过反射大法修改,方法如下
public static void addLibraryDir(String libraryPath) throws IOException {
try {
Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);
String[] paths = (String[]) field.get(null);
for (String path : paths) {
if (libraryPath.equals(path)) {
return;
}
}
String[] tmp = new String[paths.length + 1];
System.arraycopy(paths, 0, tmp, 0, paths.length);
tmp[paths.length] = libraryPath;
field.set(null, tmp);
} catch (IllegalAccessException e) {
throw new IOException("未能获得库路径的权限");
} catch (NoSuchFieldException e) {
throw new IOException("没有找到库路径");
}
}
最终代码
static {
addLibraryDir("你的动态库路径")
final String LIBRARY_NAME = "demo";
System.loadLibrary(LIBRARY_NAME);
}
# 加载动态库文件
将动态库文件放在user.dir
目录下 ,在NativeLibraryDemo
静态代码块加入如下代码
static{
final String LIBRARY_NAME = "demo";
String userDir = System.getProperty("user.dir");
if(isWindows()){
return String.format("%s/%s.dll", userDir, LIBRARY_NAME);
}
if(isLinux()){
return String.format("%s/%s.so", userDir, LIBRARY_NAME);
}
throw new RuntimeException("不支持除Windows,Linux 之外的平台");
}
# 使用
和正常java类一样使用
上次更新: 2024/11/05, 08:29:31