Java中的native关键字是什么?
当玩这个难题 (这是一个Java关键字琐事游戏),我遇到了native
关键字。
Java中使用的native关键字是什么?
native
关键字应用于一个方法,以指示该方法是使用JNI(Java Native Interface)以本地代码实现的。
它标志着一种方法,它将以其他语言而不是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)); } }
Main.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编写)
- 并将结果返回到Java
这可以用来:
- 使用更好的CPU汇编指令在关键部分编写更快的代码(不是CPU便携式)
- 直接进行系统调用(不是OS便携式)
与便携性较低的权衡。
您也可以从C中调用Java,但是您必须先在C中创建一个JVM: 如何从C ++调用Java函数?
Android NDK
在这种情况下,概念是完全一样的,除了你必须使用Android样板来设置它。
官方的NDK存储库包含“canonical”示例,如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
unzip
,您可以看到与lib/arm64-v8a/libnative-lib.so
下的本地代码相对应的预编译的.so
。
TODO确认:此外, file /data/app/com.android.appname-*/oat/arm64/base.odex
,说这是一个共享库,我认为是AOT预编译.dex对应于ART文件中的Java文件另请参阅: Android中的ODEX文件是什么? 所以也许Java实际上也是通过native
接口运行?
在OpenJDK 8中的例子
让我们找到在jdk8u60-b27中定义Object#clone
位置。
我们将得出结论,它是用native
调用来实现的。
首先我们发现:
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语言规范 :
native
方法是在平台相关的代码中实现的,通常用另一种编程语言如C,C ++,FORTRAN或汇编语言编写。native
方法的主体仅以分号给出,表示实现被省略,而不是块。
当SLaks回答时, native
关键字用于调用本地代码。
它也被GWT用来实现javascript方法。
实现本地代码的函数被声明为本地的。
Java本地接口(Java Native Interface,JNI)是一种编程框架,它使得在Java虚拟机(JVM)中运行的Java代码可以调用本地应用程序(特定于硬件和操作系统平台的程序)和被调用的库其他语言如C,C ++和程序集。
native是java中的一个关键字,用来使得像抽象一样构造未实现的结构(方法),但是它将是一个依赖于平台的本地代码,并且从本地堆栈而不是Java堆栈执行。
NATIVE是非访问修饰符,它只能应用于METHOD。 它表明了PLATFORM-DEPENDENT方法或代码的实现。
-
native
是java中的一个关键字,它表示平台依赖。 -
native
方法作为Java( JNI )和其他编程语言之间的接口。
nativ e关键字用于声明一个方法,这个方法是在平台相关的代码(如C或C ++)中实现的。 当一个方法被标记为本地的,它不能有一个正文,而必须以分号结束。 Java本地接口(JNI)规范规定了实现本地方法的规则和准则,例如Java和本地应用程序之间的数据类型转换。
以下示例显示了一个声明为native的方法
public class NativeExample { public native void fastCopyFile(String sourceFile, String destFile); }
本地方法的缺点:
-
本地方法与Windows中的.DLL(动态链接库)文件扩展名一起存储。 DLL文件是机器相关的。 因此,本地方法是不可移植的。
-
由于本地方法使用机器码,所以会导致严重的安全问题。
native关键字用于声明一个在平台相关代码(如C或C ++)中实现的方法。 当一个方法被标记为本地的,它不能有一个正文,而必须以分号结束。 Java本地接口(JNI)规范规定了实现本地方法的规则和准则,例如Java和本地应用程序之间的数据类型转换。
以下示例显示了一个声明为native的方法的类:
public class NativeExample { public native void fastCopyFile(String sourceFile, String destFile); }