虽然有看过JVM的源码,但是JNI一直是一块心病,为了克服心魔,所以手写一次.网络上都是抄来抄去的,而且历史悠久,虽然可以参考,但是还是踩了几个坑.特此记录:
首先随便建一个项目和java文件
package com.example.demo;
public class JNIDemo {
public static native void printByNative(String s);
static {
// 这个参数可以后面再来改.之前看别人用的是loadLibrary一直不行,改成load就行了
System.load("/Users/vega/git/demo/src/main/java/com/example/demo/TestJNI.jnilib");
}
public static void main(String[] args) {
String s = "111";
printByNative(s);
}
}
接着javah JNIDemo.java发现不行,原因是jdk11已经没有javah了,改成javac JNIDemo.java -h .发现文件已经生成在当前目录.文件名是com_example_demo_JNIDemo.h,显然符合JVM的规则.
接下来根据C语言的规则,h文件相当于接口,c文件相当于实现,写一个c文件.
#include <jni.h>
#include <stdio.h>
#include <com_example_demo_JNIDemo.h>
JNIEXPORT void JNICALL Java_com_example_demo_JNIDemo_printByNative
(JNIEnv * env, jobject obj, jstring content) {
const jbyte* str=(const jbyte*)(*env)->GetStringUTFChars(env,content,JNI_FALSE);
printf("Hello------->%s\n",str);
(*env)->ReleaseStringUTFChars(env,content,(const char*)str);
return;
}
然后生成TestJNI.jnilib 文件
gcc -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk-11.0.7.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk-11.0.7.jdk/Contents/Home/include/darwin/ -I /Users/vega/git/demo/src/main/java/com/example/demo/ TestJNI.c -o TestJNI.jnilib
这里gcc -I是引入需要的链接文件,比如jni.h还有com_example_demo_JNIDemo.h,总之缺什么就链接什么.在当前目录下就可以看到TestJNI.jnilib文件了.
最后运行java程序,成功输出

image.png
整个过程可以看出,我们只是用虚拟机调用了本地的C程序,又进一步的了解了JVM原理
