1 什么是当地方法
起首要知道什么是当地方法,当地方法并不是 JVM 自己的方法,也不是 jre 内里的方法,而是指那些操作体系自己的方法(如C/C++方法),它们在操作体系目录里。可以这么理解,当地方法就是计算机操作体系对外提供的方法,JVM 通过调用这些方法可以实现 Java 程序和计算机的交互。
1.1 当地方法的利益
- 访问操作体系资源:直接调用操作体系的API,例如文件体系、网络接口、图形用户界面等。
- 性能优化:对于某些计算密集型任务,利用C或C++等语言实现可以显著提高性能。
- 利用现有库:利用已经存在的C/C++库,避免重复开发和维护。
- 硬件访问:直接访问硬件设备,例如摄像头、传感器等。
所以如果我们想优化计算密集型任务的性能,或是调用 Java 中没有实现的计算机功能,我们可以自己实现一个当地方法。
1.2 声明当地方法
在Java中,当地方法通过native关键字声明。例如:- public class MyClass {
- // 声明本地方法
- public native void nativeMethod();
- // 静态块中加载本地库
- static {
- System.loadLibrary("mylib"); // 加载名为mylib的本地库
- }
- public static void main(String[] args) {
- new MyClass().nativeMethod(); // 调用本地方法
- }
- }
复制代码 1.3 实现当地方法
当地方法的实现通常利用JNI(Java Native Interface)或JNA(Java Native Access)来完成。以下是利用JNI实现当地方法的步骤:
1. 生成头文件
利用javah工具生成包罗当地方法署名的C头文件。假设上面的Java类保存为MyClass.java,编译后生成MyClass.class,然后运行:这将生成一个名为MyClass.h的头文件,内容如下:- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class MyClass */
- #ifndef _Included_MyClass
- #define _Included_MyClass
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: MyClass
- * Method: nativeMethod
- * Signature: ()V
- */
- JNIEXPORT void JNICALL Java_MyClass_nativeMethod
- (JNIEnv *, jobject);
- #ifdef __cplusplus
- }
- #endif
- #endif
复制代码 2. 编写C语言实现
根据生成的头文件,编写C语言实现。例如:- #include <jni.h>
- #include <stdio.h>
- #include "MyClass.h"
- // 实现本地方法
- JNIEXPORT void JNICALL Java_MyClass_nativeMethod(JNIEnv *env, jobject obj) {
- printf("Hello from native method!\n");
- }
复制代码 3. 编译C代码
将C代码编译成动态链接库。假设C文件名为mylib.c,编译命令如下:
在Linux上:- gcc -shared -o libmylib.so -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux mylib.c
复制代码 在Windows上:- cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD mylib.c -Fe mylib.dll
复制代码 4. 运行Java程序
确保动态链接库在Java程序的库路径中,然后运行Java程序:- java -Djava.library.path=. MyClass
复制代码 1.4 利用JNA
JNA是一种更简单的方式来调用当地库,不需要编写C代码。以下是一个利用JNA的示例:
- 添加JNA依赖:在项目中添加JNA的依赖。如果你利用Maven,可以在pom.xml中添加:
- <dependency>
- <groupId>net.java.dev.jna</groupId>
- <artifactId>jna</artifactId>
- <version>5.8.0</version>
- </dependency>
复制代码- import com.sun.jna.Library;
- import com.sun.jna.Native;
- public interface MyLib extends Library {
- MyLib INSTANCE = Native.load("mylib", MyLib.class);
- void nativeMethod();
- }
复制代码- public class MyClass {
- public static void main(String[] args) {
- MyLib.INSTANCE.nativeMethod(); // 调用本地方法
- }
- }
复制代码 1.5 总结
当地方法是Java程序中的一种特殊方法,其声明在Java代码中,但实现由非Java语言编写。通过当地方法,Java程序可以访问操作体系资源、优化性能、利用现有库和直接访问硬件设备。常见的实现方式包罗JNI和JNA。
2 当地方法栈
2.1 特点
- 线程私有:每个线程都有自己的当地方法栈,与Java虚拟机栈一样,当地方法栈也是线程私有的。
- 存储结构:当地方法栈中的每个栈帧(Frame)对应一次当地方法的调用。栈帧中包罗当地方法的参数、局部变量、操作数栈等信息。
- 调用机制:当Java代码调用一个当地方法时,JVM会创建一个新的栈帧并将其压入当地方法栈。当地方法实行完毕后,栈帧会被弹出并丢弃。
2.2 当地方法栈与Java虚拟机栈的区别
- 用途不同:Java虚拟机栈用于支持Java方法的实行,而当地方法栈用于支持当地方法的实行。
- 实现方式:Java虚拟机栈的实现由JVM规范规定,而当地方法栈的实现通常依赖于详细的JVM实现和操作体系的ABI(Application Binary Interface)。
- 数据类型:Java虚拟机栈重要处理Java类型的值,而当地方法栈可能涉及更广泛的C/C++类型或其他原生类型。
2.3 当地方法栈的工作流程
- 方法调用:当Java代码中调用一个声明为native的方法时,JVM会查找该方法的当地实现。
- 栈帧创建:JVM为当地方法创建一个新的栈帧,并将其压入当地方法栈。
- 参数传递:调用当地方法所需的参数会被从Java虚拟机栈复制到当地方法栈的栈帧中。
- 方法实行:当地方法在当地方法栈中实行,可以访问操作体系资源、硬件设备等。
- 结果返回:当地方法实行完毕后,结果会被从当地方法栈复制回Java虚拟机栈,然后继承实行Java代码。
- 栈帧弹出:当地方法栈中的栈帧被弹出并丢弃。
2.4 总结
当地方法栈是JVM中用于支持当地方法调用的重要数据结构。通过当地方法栈,Java程序可以调用用其他语言编写的代码,从而实现更广泛的功能和更高的性能。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |