在玩这个谜题(这是一个Java关键字问答游戏)时,我遇到了原生关键字。
Java中的本机关键字用于什么?
在玩这个谜题(这是一个Java关键字问答游戏)时,我遇到了原生关键字。
Java中的本机关键字用于什么?
当前回答
实现本机代码的函数被声明为本机。
Java本机接口(JNI)是一个编程框架,它使运行在Java虚拟机(JVM)中的Java代码能够调用本机应用程序(特定于硬件和操作系统平台的程序)和用其他语言(如C、c++和汇编)编写的库,并被它们调用。
http://en.wikipedia.org/wiki/Java_Native_Interface
其他回答
本机关键字应用于方法,以指示该方法是使用JNI (Java本机接口)在本机代码中实现的。
它标记了一个方法,它将在其他语言中实现,而不是在Java中。它与JNI (Java本机接口)一起工作。
在过去,本机方法用于编写性能临界区,但随着Java的速度越来越快,这种方法现在不太常见了。当前需要本机方法时
您需要从Java调用用其他语言编写的库。 您需要访问只能通过其他语言(通常是C语言)访问的系统或硬件资源。实际上,许多与真实计算机交互的系统函数(例如磁盘和网络IO)只能这样做,因为它们调用本机代码。
另请参阅 Java本机接口规范
最小可运行示例
Main.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 AMD64上测试。还使用过Oracle JDK 1.8.0_45。
在GitHub上的例子供你使用。
Java包/文件名称中的下划线必须在C函数名中使用_1转义,如前所述:在包含下划线的Android包名称中调用JNI函数
解释
本机允许您:
用Java中的任意汇编代码调用已编译的动态加载库(这里用C编写) 并将结果返回到Java中
这可以用于:
用更好的CPU组装指令在临界区编写更快的代码(不是CPU可移植的) 直接进行系统调用(不能移植操作系统)
以降低可移植性为代价。
你也可以从C调用Java,但你必须先用C创建一个JVM:如何从c++调用Java函数?
由于同样的原因,类似的本地扩展api也出现在许多其他“VM语言”中,例如Python、Node.js、Ruby。
Android NDK
在这个上下文中,概念是完全相同的,除了必须使用Android样板来设置它。
官方的NDK存储库包含“规范”的示例,例如hello-jni应用程序:
https://github.com/googlesamples/android-ndk/blob/4df5a2705e471a0818c6b2dbc26b8e315d89d307/hello-jni/app/src/main/java/com/example/hellojni/HelloJni.java#L39 https://github.com/googlesamples/android-ndk/blob/4df5a2705e471a0818c6b2dbc26b8e315d89d307/hello-jni/app/src/main/cpp/hello-jni.c#L27
当你在Android O上用NDK解压一个。apk时,你可以看到预编译的。所以这对应于lib/arm64-v8a/libnative-lib.so下的本机代码。
TODO确认:此外,文件/data/app/com.android.appname-*/oat/arm64/base。odex,说它是一个共享库,我认为是AOT预编译的。dex对应于ART中的Java文件,另见:Android中的odex文件是什么?也许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
这将导致我们进入hotspot/src/share/vm/prims/jvm.cpp#l580:
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");
在展开了一堆宏之后,我们得出结论,这就是定义点。
实现本机代码的函数被声明为本机。
Java本机接口(JNI)是一个编程框架,它使运行在Java虚拟机(JVM)中的Java代码能够调用本机应用程序(特定于硬件和操作系统平台的程序)和用其他语言(如C、c++和汇编)编写的库,并被它们调用。
http://en.wikipedia.org/wiki/Java_Native_Interface
正如SLaks回答的那样,native关键字用于调用本机代码。
它也被GWT用来实现javascript方法。