Java中的native关键字是什么?

时间:2011-05-23 18:29:45

标签: java java-native-interface native keyword

在玩this puzzle(这是一个Java关键字琐事游戏)时,我遇到了native关键字。

Java中使用的native关键字是什么?

9 个答案:

答案 0 :(得分:405)

它标记了一种方法,它将用其他语言实现,而不是用Java实现。它与JNI(Java Native Interface)一起使用。

过去使用本机方法来编写性能关键部分,但随着Java变得越来越快,现在不太常见了。

目前需要原生方法
  • 您需要从Java调用用其他语言编写的库。

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

另见 Java Native Interface Specification

答案 1 :(得分:403)

最小的例子让事情变得更加清晰:

<强> 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。

Example on GitHub让你玩。

Java包/文件名中的下划线必须在C函数名称中使用_1进行转义,如下所述:Invoking JNI functions in Android package name containing underscore

<强>解释

它允许您:

  • 使用Java
  • 中的任意汇编代码调用已编译的动态加载库(此处使用C语言编写)
  • 并将结果反馈回Java

这可以用于:

  • 使用更好的CPU汇编指令(不是CPU便携式)在关键部分写入更快的代码
  • 进行直接系统调用(不是OS便携式)

与较低的便携性进行权衡。

您也可以从C调用Java,但必须先在C中创建JVM:How to call Java functions from C++?

Android NDK

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

官方NDK存储库包含“规范”示例,例如hello-jni app:

在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文件,另请参阅:What are ODEX files in Android?所以也许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

引导我们hotspot/src/share/vm/prims/jvm.cpp#l580

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

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

答案 2 :(得分:317)

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

答案 3 :(得分:57)

直接来自the Java Language Specification

  

native方法是在依赖于平台的代码中实现的,通常用其他编程语言编写,例如C,C ++,FORTRAN或汇编语言。 native方法的主体仅以分号给出,表示省略了实现,而不是块。

答案 4 :(得分:19)

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

它也被GWT用于实现javascript方法。

答案 5 :(得分:13)

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

  

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

http://en.wikipedia.org/wiki/Java_Native_Interface

答案 6 :(得分:8)

NATIVE是非访问修饰符。它只能应用于METHOD。 它表示方法或代码的PLATFORM-DEPENDENT实现。

答案 7 :(得分:6)

native是java中的一个关键字,用于制作未实现的结构(方法),如抽象,但它将依赖于平台,如本机代码,从本机堆栈执行而不是java堆栈。

答案 8 :(得分:3)

由于功能或性能原因,Java native方法为Java代码提供了一种调用OS本机代码的机制。

示例:

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();

Runtime.class中OpenJDK的相应JAVA_HOME/jmods/java.base.jmod/classes/java/lang/Runtime.class文件中,包含这些方法并用ACC_NATIVE0x0100)标记,并且这些方法不包含Code attribute,这意味着这些方法在Runtime.class文件中没有任何实际的编码逻辑:

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

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的{​​{1}}(Linux)或libjava.dll(Windows)文件中:

enter image description here

enter image description here

参考