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函数名称中用_1转义,如下所述:在Android包名称中调用包含下划线的JNI函数

    解释

    它允许你:

  • 使用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上的NDK unzip.apk时,你可以看到与lib/arm64-v8a/libnative-lib.so下的本地代码相对应的预编译的.so

    TODO确认:另外, file /data/app/com.android.appname-*/oat/arm64/base.odex表示它是一个共享库,我认为它是对应于ART中的Java文件的AOT预编译.dex ,另请参阅: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");
    

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

    链接地址: http://www.djcxy.com/p/2863.html

    上一篇: What is the native keyword in Java for?

    下一篇: What is the purpose of backbone.js?