实现
首先保证我们的环境是ok的
- gcc
- openjdk
直接用apt-get install安装即可,百度一查很多教程
首先我们创建下目标java文件
public class HelloNative {
static {
System.loadLibrary("HelloNative");
}
public static native void sayHello();
public static void main(String[] args) {
new HelloNative().sayHello();
}
}
完成之后,我们需要获取对应的.h文件
# 编译java文件
javac HelloNative.java
# 获取头文件
javah HelloNative
然后我们就会获得一个HelloNative.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */
#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloNative
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloNative_sayHello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
不要动,我们需要新建一个对应的HelloNative.c文件来实现定义的native方法sayHello
#include <stdio.h>
#include "HelloNative.h"
JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *env, jclass jc) {
printf("Hello Native!\n");
}
ok,现在里成功已经差半步了
我们需要对c文件进行编译获取.so动态链接库供java文件调用
g++ -fPIC -shared HelloNative.c -o libHelloNative.so
此时就ok了,看看效果
java HelloNative
对应有输出结果,ok的!
踩坑
看起来一帆风顺,实际上踩了不少坑
添加头文件
开始编译c会提示找不到jni.h和jni_md.h,这两个文件是jdk中的,没有加入到搜索include目录下,可以直接ln建立链接或者cp过去
动态链接库路径
因为之前写过cpp,对于linux下c链接.so是有默认路径的,我们生成的.so路径可能不在其中,因此需要将.so所在的路径添加到搜索路径中
通常采用export指令即可(临时)
对于我来说,通常采用这个指令:
export LD_LIBRARY_PATH=$(pwd):${LD_LIBRARY_PATH}
这里:的作用就是分割不同路径,和环境变量PATH写法是一样的
其中:
$()是获取指令结果
${}是获取变量值
找不到.so
已经指定了路径,但是仍然会抛出异常问题
Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1124)
at HelloNative.<clinit>(HelloNative.java:3)
很头大,根据exception提示还是说找不到.so
在网上查了半天,发现是和命名机制相关,我们在loadLibrary的时候是有修改的
loadLibrary(“XXX”);
实际上对应的.so为libXXX.so
因此我们在生成.so命名的时候别忘了前缀lib