JNI(Java Native Interface),通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。
1、java新建类HelloWorld,并声明native方法,引入hello的dll
public class HelloWorld {
public native void hello();
static{
System.loadLibrary("hello");
}
public static void main(String[] args){
new HelloWorld().hello();
}
}
2、编译生成.class文件
javap HelloWorld.java
3、使用javah生成.h头文件,【生成的HelloWorld.h 不要做任何修改】
javah HelloWorld
文件明细如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: hello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
4、使用C或C++实现hello()方法
#include "jni.h"
#include "HelloWorld.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloWorld_hello(JNIEnv *env,jobject obj){
printf("Hello World!\n");
return;
}
5、将jni_md.h文件拷贝到include文件夹下
sudo cp /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/include/darwin/jni_md.h /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/include
6、将.c文件编译并生成动态链接库
其中:/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/include
替换为本地的jdk路径中的include文件路径
gcc -dynamiclib -I /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/include HelloWorldImpl.c -o libhello.jnilib
gcc -dynamiclib -I 这里是include路径 HelloWorldImpl.c -o libhello.jnilib
生成的动态链接库,libhello.jnilib 对应 java代码中的 hello,这里映射大小写不敏感
也就是libhello.jnilib 可以映射到 HELLO、hello、Hello、HellO等
也就是libHELLO.jnilib 可以映射到 HELLO、hello、Hello、HellO等
7、查看当前目录文件信息
8、运行java的main方法
java HelloWorld
9、查看HelloWorld的字节码
javap -c -v HelloWorld.class > HelloWorld.txt
字节码如下所示:
Classfile /Users/pfzheng/Downloads/demo/HelloWorld.class
Last modified 2023-2-7; size 442 bytes
MD5 checksum 21235e46a38830416fd799866dd7b048
Compiled from "HelloWorld.java"
public class HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#18 // java/lang/Object."<init>":()V
#2 = Class #19 // HelloWorld
#3 = Methodref #2.#18 // HelloWorld."<init>":()V
#4 = Methodref #2.#20 // HelloWorld.hello:()V
#5 = String #12 // hello
#6 = Methodref #21.#22 // java/lang/System.loadLibrary:(Ljava/lang/String;)V
#7 = Class #23 // java/lang/Object
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 hello
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 <clinit>
#16 = Utf8 SourceFile
#17 = Utf8 HelloWorld.java
#18 = NameAndType #8:#9 // "<init>":()V
#19 = Utf8 HelloWorld
#20 = NameAndType #12:#9 // hello:()V
#21 = Class #24 // java/lang/System
#22 = NameAndType #25:#26 // loadLibrary:(Ljava/lang/String;)V
#23 = Utf8 java/lang/Object
#24 = Utf8 java/lang/System
#25 = Utf8 loadLibrary
#26 = Utf8 (Ljava/lang/String;)V
{
public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
public native void hello();
descriptor: ()V
flags: ACC_PUBLIC, ACC_NATIVE
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: new #2 // class HelloWorld
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method hello:()V
10: return
LineNumberTable:
line 15: 0
line 16: 10
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #5 // String hello
2: invokestatic #6 // Method java/lang/System.loadLibrary:(Ljava/lang/String;)V
5: return
LineNumberTable:
line 10: 0
line 11: 5
}
SourceFile: "HelloWorld.java"
在上述字节码中可以看到hello()方法,被标识为ACC_NATIVE
10、安装IDEA插件jclasslib 查看字节码
插件主页:https://plugins.jetbrains.com/plugin/9248-jclasslib-bytecode-viewer
安装成功后,在View -> Show Bytecode with jclasslib
作者: 伊甸一点
本文版权归作者伊甸一点有,欢迎转载和商用(须保留此段声明),且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.