如果我们查看 Java Object 类,那么我们可以找到一些方法,例如:
public native int hashCode()
protected native Object clone()
这些本地人是什么?这些方法是如何工作的?
如果我们查看 Java Object 类,那么我们可以找到一些方法,例如:
public native int hashCode()
protected native Object clone()
这些本地人是什么?这些方法是如何工作的?
这些方法要么是内在的,要么是在 Java 之外以“本机”代码编写的,即特定于给定机器。
您提到的是Intrinsic和 JDK 的一部分,但您也可以使用Java 本机接口(JNI) 自己编写本机方法。这通常会使用 C 来编写方法,但许多其他语言,例如 python,允许您相当容易地以这种方式编写方法。以这种方式编写代码要么是为了提高性能,要么是因为它需要访问平台特定的基础设施,而这在纯 java 中是无法完成的。
在 的情况下hashcode()
,这是由 JVM 实现的。这是因为哈希码通常与只有 JVM 知道的东西相关。在早期的 JVM 上,这与对象在内存中的位置有关——在其他 JVM 上,对象可能会在内存中移动,因此可以使用更复杂(但仍然非常快)的方案。
如其他答案中所述,大多数本机方法都是使用 JNI 实现的。
但是,性能关键方法(例如,Object.hashCode
通常作为内在函数实现)。当字节码被编译成机器码时,Java 编译器会识别方法调用并直接内联适当的代码。这显然比通过 JNI 获得一个简单的方法要快得多。
许多人会声称Object.hashCode
将返回内存中对象表示的地址。在现代实现中,对象实际上在内存中移动。取而代之的是,对象头的一个区域用于存储该值,该值可能是在首次请求该值时从内存地址中延迟派生的。
本机方法主要在 C 中实现,并编译为直接在机器上运行的本机代码。这与在 Java 中实现并编译为由 Java 虚拟机 (JVM) 执行的 Java 字节码的普通方法形成对比。
要从 Java 与这些方法交互,您需要使用Java Native Interface (JNI)。
本机代码主要用于访问低级内容。在hashCode的情况下,这是内存中对象的地址。我对克隆的猜测是它将原始内存从给定对象复制到克隆对象。本机代码的其他用途是访问操作系统功能或硬件。
使用本机代码的缺点是您失去了 JVM 的安全性,即您的程序可能由于本机代码中的错误而崩溃或存在安全漏洞。
这些本地人是什么?这些方法是如何工作的?
使事情更清楚的最小示例:
主.java:
public class Main {
public native int square(int i);
public static void main(String[] args) {
System.loadLibrary("Main");
System.out.println(new Main().square(2));
}
}
主.c:
#include <jni.h>
#include "Main.h"
JNIEXPORT jint JNICALL Java_Main_square(
JNIEnv *env, jobject obj, jint i) {
return i * i;
}
编译并运行:
sudo apt-get install build-essential openjdk-7-jdk
export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-amd64'
javac Main.java
javah -jni Main
gcc -shared -fpic -o libMain.so -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/linux Main.c
java -Djava.library.path=. Main
输出:
4
在 Ubuntu 14.04 上测试。还与 Oracle JDK 1.8.0_45 一起使用。
GitHub 上的示例供您使用。
解释:
它允许您:
这可用于:
以较低的便携性为代价。
您也可以从 C 调用 Java,但您必须先在 C 中创建一个 JVM:如何从 C++ 调用 Java 函数?
OpenJDK 8 中的示例
让我们找到Object#clone
在jdk8u60-b27中定义的位置。
首先我们发现:
find . -name Object.java
这导致我们到jdk/src/share/classes/java/lang/Object.java#l212:
protected native Object clone() throws CloneNotSupportedException;
现在是困难的部分,找到克隆在所有间接中的位置。帮助我的查询是:
find . -iname object.c
它将找到可能实现 Object 的本机方法的 C 或 C++ 文件。它引导我们到jdk/share/native/java/lang/Object.c#l47:
static JNINativeMethod methods[] = {
...
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
这将我们引向JVM_Clone
符号:
grep -R JVM_Clone
这将我们带到了热点/src/share/vm/prims/jvm.cpp#l580:
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
展开一堆宏后,我们得出结论,这就是定义点。
Java 中的本机方法是使用称为 JNI的“ Java 本机接口”实现的。