1.背景:今天学习多线程,多留意了一下 Thread 类中的 setPriority 方法,发现设置线程优先级别的时候有一个方法“setPriority0”。光看名字就觉得有点奇怪。于是继续探索他到底是怎么实现的,发现java并没有实现该方法,只有"private native void setPriority0(int newPriority);",然后"native" 这个关键字引起我的注意,虽然之前学到过有点印象,不过好像没怎么用过。仔细一查,原来是关于 JNI 方面的知识。
2.关于JNI:Java Native Interface,他是作为方便java语言和其他的语言进行交互通信而设计的一种技术。其实早在java1.1,JNI技术已经被运用到java平台中。这门技术之所以存在,是因为java设计上的权限,作为跨平台的语言,能够在windows和linux等多操作系统上运行,必然会牺牲一些对底层的控制的权利,换言之,java并不能与操作系统的底层进行交互。为此,需要用native的方法来弥补这一缺陷。目的是让java也能够调用c/c++来与硬件,操作系统实现交互。
3.native关键字的用法:
(1)在java中声明native的方法
(2)用javah命令来自动生成头文件
(3)用c/c++来实现头文件中的方法,注意在复制相关方法时候,需要给定参数的名称
(4)将第三步骤中的文件编译生成动态链接库文件
(5)在Java代码中如果需要使用,用System.loadLibrary()方法加载第四步中的动态链接库文件,这个native()就能够被我们的java代码所使用了。
4.具体操作如下:
(1)在java中声明native的方法
public class HelloNative {
static {
System.loadLibrary("HelloNative");
}
public static native void sayHello();
public static void main(String[] args) {
new HelloNative().sayHello();
}
}
(2)用javah命令来自动生成头文件
javac HelloNative.java
javah HelloNative
这样就产生了HelloNative.h的头文件,现文件目录如下:
其中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
注意到Java_HelloNative_sayHello,就是我们定义的方法,可以看到格式为Java_类名称_方法名称。
(3)用c/c++来实现头文件中的方法,注意在复制相关方法时候,需要给定参数的名称
#include <jni.h>
#include <stdio.h>
#include "HelloNative.h"
JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv* env, jclass obj)
{
printf("Hello,JNI");
return;
}
这里面有一个注意点,我们很容易把头文件的方法复制过来,请注意,方法参数中Java_HelloNative_sayHello(JNIEnv* env, jclass obj)需要设置方法名称,否则后续生成dll文件会报错,注意编程的细节。
(4)将第三步骤中的文件编译生成动态链接库文件
gcc -m64 -Wl,--add-stdcall-alias -I"D:\Java\jdk1.8.0_181\include" -I"D:\Java\jdk1.8.0_181\include\win32" -shared -o HelloNative.dll HelloNative.c
请注意自己的jdk安装的位置。
这时候我们会发现多了一个dll文件:
(5)在Java代码中如果需要使用,用System.loadLibrary()方法加载第四步中的动态链接库文件,这个native()就能够被我们的java代码所使用了。
java HelloNative
运行结果如下:
至此我们初次对native关键字的探索前进了一步。