举个例子,在下面这段代码中,Foo
类有一个 native 方法bar
。
package diveinjvm;
public class Foo {
public native void bar(String s, Object o);
}
我们把文件复制到虚拟机里,这里用的是centos7.4。
然后执行命令:javac -h . Foo.java
可以看到生成了一个 diveinjvm_Foo.h文件
具体文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class diveinjvm_Foo */
#ifndef _Included_diveinjvm_Foo
#define _Included_diveinjvm_Foo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: diveinjvm_Foo
* Method: bar
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_diveinjvm_Foo_bar
(JNIEnv *, jobject, jstring, jobject);
#ifdef __cplusplus
}
#endif
#endif
我们来填充这个方法,编写一个foo.c
具体内容如下;
#include <stdio.h>
#include "diveinjvm_Foo.h"
JNIEXPORT void JNICALL Java_diveinjvm_Foo_bar__Ljava_lang_String_2Ljava_lang_Object_2(JNIEnv *env, jobject thisObject, jstring str, jobject obj) {
printf("Hello, World\n");
return;
}
编译foo.c
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared foo.c -o libfoo.so
我们在Foo.java中调用这个方法
具体代码
package diveinjvm;
public class Foo {
// public static native void foo();
// public native void bar(int i, long j);
public native void bar(String s, Object o);
int i = 0xDEADBEEF;
public static void main(String[] args) {
try {
System.loadLibrary("foo");
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
System.exit(1);
}
new Foo().bar("", "");
}
}
编译: javac diveinjvm/Foo.java
执行结果:
[root@node1 jnidemo]# java diveinjvm.Foo
Hello, World
可能遇到的问题:
1.Error: Could not find or load main class diveinjvm.Foo
这里我把Foo.java放到了diveinjvm文件夹下编译的,这个要特别注意
还有一个解决办法 就是 删除package声明 或者 编译的时候 javac Foo.java -d .
这里会自动生成diveinjvm文件夹
2.java.lang.UnsatisfiedLinkError: no foo in java.library.path
这里我们有三种解决方法:
- 执行时指定:java -Djava.library.path=/home/jnidemo/libfoo.so diveinjvm.Foo
- export LD_LIBRARY_PATH=/home/jnidemo/ 然后执行 java diveinjvm.Foo
- 编辑 /etc/profile 文件 在文件末尾添加 export LD_LIBRARY_PATH=/home/jnidemo/ 然后 source /etc/profile