Java中的原生关键字是干什么用的?

在玩这个谜题(这是一款Java关键字问答游戏)时,我遇到了native关键字。

Java中的本机关键字用于什么?

254518 次浏览

native关键字应用于方法,以指示该方法是使用JNI (Java本机接口)在本机代码中实现的。

正如SLaks回答的,native关键字用于调用本机代码。

GWT也使用它来实现javascript方法。

它标记了一个方法,它将在其他语言中实现,而不是在Java中。它与JNI (Java本机接口)一起工作。

在过去,本机方法用于编写性能临界区,但随着Java的速度越来越快,这种方法现在不太常见了。当前需要本机方法时

  • 您需要从Java调用用其他语言编写的库。

  • 您需要访问只能通过其他语言(通常是C语言)访问的系统或硬件资源。实际上,许多与真实计算机交互的系统函数(例如磁盘和网络IO)只能这样做,因为它们调用本机代码。

< p >见也 # EYZ0 < / p >

直接来自Java语言规范:

native的方法是在依赖于平台的代码中实现的,通常是用另一种编程语言(如C、c++、FORTRAN或汇编语言)编写的。native方法的主体仅以分号形式给出,表示省略了实现,而不是一个块。

实现本机代码的函数被声明为本机。

Java本机接口(JNI)是一个编程框架,它使运行在Java虚拟机(JVM)中的Java代码能够调用本机应用程序(特定于硬件和操作系统平台的程序)和用其他语言(如C、c++和汇编)编写的库,并被它们调用。

http://en.wikipedia.org/wiki/Java_Native_Interface < a href = " http://en.wikipedia.org/wiki/Java_Native_Interface " > < / >

Native是Java中的一个关键字,用于使未实现的结构(方法)成为抽象的,但它将是依赖于平台的,例如本机代码,并从本机堆栈而不是Java堆栈执行。

NATIVE是非访问修饰符。它只能应用于METHOD。 它表示方法或代码的平台依赖的实现

最小可运行示例

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函数所述

解释

native允许你:

  • 用Java中的任意汇编代码调用已编译的动态加载库(这里用C编写)
  • 并将结果返回到Java中

这可以用于:

  • 用更好的CPU组装指令在临界区编写更快的代码(不是CPU可移植的)
  • 直接进行系统调用(不能移植操作系统)

以降低可移植性为代价。

你也可以从C调用Java,但是你必须先在C: 如何从c++调用Java函数?中创建一个JVM

由于同样的原因,类似的本地扩展api也出现在许多其他“VM语言”中,例如Pythonnode . jsRuby

Android NDK

在这个上下文中,概念是完全相同的,除了必须使用Android样板来设置它。

官方的NDK存储库包含“规范”的示例,例如hello-jni应用程序:

在Android O上使用NDK的unzip.apk中,你可以看到预编译的.so对应于lib/arm64-v8a/libnative-lib.so下的本机代码。

TODO确认:此外,file /data/app/com.android.appname-*/oat/arm64/base.odex,说它是一个共享库,我认为这是AOT预编译的。dex对应于ART中的Java文件,另见:Android中的ODEX文件是什么?所以也许Java实际上也通过native接口运行?

OpenJDK 8中的示例

让我们找到Object#clone在jdk8u60-b27中定义的位置。

我们将得出结论,它是通过native调用实现的。

首先我们发现:

find . -name Object.java

这就引出了jdk / src /分享/类/ java / lang / Object.java # l212:

protected native Object clone() throws CloneNotSupportedException;

现在困难的部分来了,在所有的间接中找到克隆在哪里。对我有帮助的问题是:

find . -iname object.c

它可以找到可能实现Object的本机方法的C或c++文件。它将我们引向jdk /分享/本地/ java / lang / Object.c #力争:

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 vm / src /分享/ / / jvm.cpp # l580带出严肃的:

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
JVMWrapper("JVM_Clone");

在展开了一堆宏之后,我们得出结论,这就是定义点。

  • native是java中的关键字,它表示依赖于平台。
  • native方法充当Java(JNI)和其他编程语言之间的接口。

java# EYZ0方法提供了一种机制,使Java代码可以调用操作系统本机代码,无论是出于功能原因还是性能原因。

例子:

606  public native int availableProcessors();
617  public native long freeMemory();
630  public native long totalMemory();
641  public native long maxMemory();
664  public native void gc();

在OpenJDK中对应的Runtime.class文件中,位于JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class,包含这些方法,并标记为ACC_NATIVE (0x0100),这些方法不包含代码属性,这意味着这些方法在Runtime.class文件中没有任何实际的编码逻辑:

  • 方法13 availableProcessors:标记为本机,没有Code属性
  • 方法14 freeMemory:标记为本机,没有Code属性
  • 方法15 totalMemory:标记为本机,没有Code属性
  • 方法16 maxMemory:标记为本机,没有Code属性
  • 方法17 gc:标记为本机,没有Code属性

enter image description here

实际上编码逻辑在相应的Runtime.c文件中:

42  #include "java_lang_Runtime.h"
43
44  JNIEXPORT jlong JNICALL
45  Java_java_lang_Runtime_freeMemory(JNIEnv *env, jobject this)
46  {
47      return JVM_FreeMemory();
48  }
49
50  JNIEXPORT jlong JNICALL
51  Java_java_lang_Runtime_totalMemory(JNIEnv *env, jobject this)
52  {
53      return JVM_TotalMemory();
54  }
55
56  JNIEXPORT jlong JNICALL
57  Java_java_lang_Runtime_maxMemory(JNIEnv *env, jobject this)
58  {
59      return JVM_MaxMemory();
60  }
61
62  JNIEXPORT void JNICALL
63  Java_java_lang_Runtime_gc(JNIEnv *env, jobject this)
64  {
65      JVM_GC();
66  }
67
68  JNIEXPORT jint JNICALL
69  Java_java_lang_Runtime_availableProcessors(JNIEnv *env, jobject this)
70  {
71      return JVM_ActiveProcessorCount();
72  }

这些C编码被编译成libjava.so (Linux)或libjava.dll (Windows)文件,位于JAVA_HOME/jmods/java.base.jmod/lib/libjava.so:

enter image description here

enter image description here

参考