Object
Object是所有类的父类。
方法结构如下
一些不知道的方法
private static native void registerNatives();
* JNI机制
* 这里定义了一个 native 方法 registerNatives(),它没有方法体。
* native 关键字表示这个方法的实现是由本地代码
* (通常是 C 或 C++ 代码)提供的,而不是由 Java 提供。
* 该方法通常通过 Java Native Interface(JNI)调用本地代码。
*/
protected native Object clone() throws CloneNotSupportedException;
解释:
*子类,使用时必须实现 Cloneable 接口,并且它的拷贝时浅拷贝*
protected void finalize() throws Throwable { }
解释:
释放系统资源 或 执行其他清理任务
* 在gc的时候会被调用
*
* finalize()在现代Java开发中已经被视为过时和不推荐使用的方式。
* JVM中对它的调用时机不可控,可能导致资源无法及时释放。
* 在Java 9及以后版本中,Java更推荐使用try-with-resources或显式资源管理(如close()方法)
* 来管理资源,而不依赖于finalize()。
*
* 总结来说,finalize()是一个被设计用于资源清理的机制,
* 但由于其不可预测性和性能问题,逐渐被更好的替代方案取代。
JNI机制是什么?
JNI(Java Native Interface,Java本地接口)是一种允许Java代码与其他编程语言(通常是C或C++)编写的本地代码进行交互的机制。它是Java平台的一个重要组成部分,提供了一种调用和访问本地代码库、系统资源或者是无法用纯Java实现的功能的途径。
JNI的主要特点和作用
- 跨语言互操作性:
- JNI使得Java程序可以调用其他编程语言(主要是C和C++)编写的本地函数,反之,本地代码也可以调用Java代码。这在需要与操作系统的底层功能或现有的本地库交互时尤为有用。
- 平台相关性:
- Java是一种跨平台的编程语言,通过JNI调用本地代码会打破这种跨平台性,因为本地代码是针对特定平台(操作系统和硬件)的。调用本地代码通常需要编译不同的二进制文件来适应不同的操作系统,如Windows、Linux、macOS等。
- 性能提升:
- 使用JNI可以在某些场景下提高性能,尤其是在需要频繁使用低级别系统功能或需要执行高效的计算时。C和C++等语言在某些情况下比Java具有更高的执行效率。
- 扩展功能:
- 有时,某些操作系统特有的功能或硬件相关的操作无法直接用Java实现,JNI可以用来扩展Java程序的功能,调用系统API或硬件设备驱动程序。
JNI工作机制
-
加载本地库:
- 使用
System.loadLibrary()
方法加载一个动态链接库(如.dll
、.so
或.dylib
),这些库通常是用C或C++编写并编译的。
System.loadLibrary("myNativeLib");
- 使用
-
声明本地方法:
- 在Java中,声明本地方法时使用
native
关键字,表明该方法没有用Java实现,而是由本地代码提供。
public class MyClass { public native void myNativeMethod(); }
- 在Java中,声明本地方法时使用
-
C/C++实现:
- 对应的本地方法需要在C或C++中实现。使用工具
javah
生成Java类对应的C/C++头文件,或者通过手动映射,确保方法签名匹配。
#include <jni.h> JNIEXPORT void JNICALL Java_MyClass_myNativeMethod(JNIEnv *env, jobject obj) { // 实现具体的功能 }
- 对应的本地方法需要在C或C++中实现。使用工具
-
调用本地方法:
- 一旦本地库加载完成并且本地方法实现了,Java代码就可以像调用普通Java方法一样调用本地方法。
JNI的主要组成部分
JNIEnv
:JNIEnv
是一个指向结构体的指针,它提供了一系列用于操作Java对象、调用Java方法、以及处理异常的函数。每个本地方法的第一个参数通常是JNIEnv *env
。
jobject
:jobject
是对Java对象的引用,C/C++代码可以通过它操作Java对象,如调用对象的方法或访问其属性。
JNIEXPORT
和JNICALL
:- 这些宏是JNI函数声明中的标准修饰符,
JNIEXPORT
用于表明函数是导出的(供Java调用),而JNICALL
定义调用约定。
- 这些宏是JNI函数声明中的标准修饰符,
- 类型签名:
- JNI使用一种特定的方式表示Java中的数据类型和方法签名。例如,
I
表示int
,Ljava/lang/String;
表示String
类。
- JNI使用一种特定的方式表示Java中的数据类型和方法签名。例如,
JNI常见用途
- 与操作系统交互:
- 通过JNI可以调用操作系统特有的API,执行文件操作、访问硬件设备、调用系统级服务等。
- 调用已有的本地库:
- 有些已有的库(如硬件驱动程序、优化算法库)是用C/C++编写的,Java程序可以通过JNI调用这些库。
- 提高性能:
- 某些计算密集型的任务,尤其是需要大量数学运算或实时处理的场景(如音视频处理、图形渲染),可以通过JNI调用C/C++代码来提高性能。
- 访问特定硬件:
- JNI可以直接访问特定平台上的硬件,如传感器、摄像头等设备,这对于嵌入式系统或移动设备编程尤为重要。
JNI的局限性
- 复杂性: JNI的使用增加了开发的复杂性,Java和C/C++之间的互操作代码比较难写、难调试。
- 跨平台问题: 本地代码是平台相关的,需要为不同的平台分别编译二进制文件,破坏了Java跨平台的优点。
- 安全性问题: 本地代码可能引入安全漏洞,如内存泄漏、缓冲区溢出等问题,Java本身对这些问题有很好的保护,但本地代码需要手动管理。
总结
JNI是一种强大的工具,允许Java应用程序调用和交互C/C++等本地代码。它在需要提高性能、调用系统资源或与现有本地库集成时发挥重要作用,但同时也带来了复杂性和跨平台挑战。在实际开发中,除非必要,通常更倾向于用纯Java或第三方Java库来解决问题,而JNI适合需要本地代码支持的特定场景。