Java中的native关键字是什么?

whi*_*win 455 java java-native-interface native keyword

在玩这个谜题(这是一个Java关键字琐事游戏)时,我遇到了native关键字.

Java中的native关键字用于什么?

Cir*_*四事件 422

使事情更清晰的最小例子:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

Main.c:

#include <jni.h>
#include "Main.h"

JNIEXPORT jint JNICALL Java_Main_square(
    JNIEnv *env, jobject obj, jint i) {
  return i * i;
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

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
Run Code Online (Sandbox Code Playgroud)

输出:

4
Run Code Online (Sandbox Code Playgroud)

在Ubuntu 14.04 AMD64上测试.还使用了Oracle JDK 1.8.0_45.

GitHub上的示例供您玩.

必须使用_1C函数名转义Java包/文件名中的下划线,如下所述:在包含下划线的Android包名中调用JNI函数

解释:

它允许您:

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

这可以用于:

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

与低便携性的权衡.

您也可以从C调用Java,但必须首先在C中创建JVM:如何从C++调用Java函数?

Android NDK

除了您必须使用Android样板来设置它之外,这个概念在此上下文中完全相同.

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

在您unzip.apk使用NDK Android上的O,你可以看到预编译.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#clonejdk8u60-b27中定义的位置.

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

首先我们发现:

find . -name Object.java
Run Code Online (Sandbox Code Playgroud)

这导致我们jdk/src/share/classes/java/lang/Object.java#l212:

protected native Object clone() throws CloneNotSupportedException;
Run Code Online (Sandbox Code Playgroud)

现在是困难的部分,找到克隆在所有间接中的位置.帮助我的查询是:

find . -iname object.c
Run Code Online (Sandbox Code Playgroud)

可以找到可能实现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]));
}
Run Code Online (Sandbox Code Playgroud)

这导致我们的JVM_Clone符号:

grep -R JVM_Clone
Run Code Online (Sandbox Code Playgroud)

这导致我们到hotspot/src/share/vm/prims/jvm.cpp#l580:

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
    JVMWrapper("JVM_Clone");
Run Code Online (Sandbox Code Playgroud)

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

  • @Ciro对于那些以您的示例开头的人来说是一些额外的信息(SO上大约有300的答案可以作为参考)。我有一个函数,该函数带有不正确的签名,在堆栈上称为混乱,没有报告错误(在编译,链接或运行时)。因此,我认为在此步骤中要提请注意非常重要。 (2认同)

Orh*_*nar 412

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

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

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

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

另请参阅 Java本地接口规范

  • 像@ currentTimeMillis这样的@MKod方法是JDK的一部分,它们用`native`注释,因为实现是在JDK源代码本身.实现使用汇编语言的可能性很小; 它可能会调用JVM运行的操作系统的API方法.例如,在Windows上,它可能会调用kernel32.dll中的DLL方法`GetSystemTime`.在另一个操作系统上,它将具有不同的实现.但是,当您使用`native`作为您正在编写的方法(而不是JDK方法)时,您必须使用JNI提供实现. (4认同)
  • 这是我的理解我在java文件中编写System.currentTimeMillis()(本机)然后这个工作,JNI将调用库或用C或C++或汇编语言编写的一些函数然后将一些值返回给我的java代码.例如:currentTimeMillis方法在JNI的帮助下调用本机代码,并且本机代码与系统资源对话:坐在主板上的计时器,从而获得返回值(系统时间).请帮我. (3认同)
  • @flow2k 并非每个“本机”方法都使用 JNI。对于 JVM 已知的 JRE 方法,可以有其他机制。例如`Object.getClass()`不会使用JNI。但对于应该在不同兼容 JVM 上运行的本机应用程序方法,JNI 是标准接口。 (2认同)

SLa*_*aks 328

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

  • 实际的实现不必使用JNI。某些JRE方法由JVM内部处理。实际上,实现实际上不是“本机”代码甚至不是强制性的。它只是[“使用Java编程语言以外的其他语言实现”](https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.6-200-A .1)。 (3认同)

Pop*_*ops 57

直起Java语言规范:

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


小智 19

正如SLaks所回答的那样,该native关键字用于调用本机代码.

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


Ade*_*lin 13

实现本机代码的函数声明为native.

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

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


Ree*_*ika 8

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


小智 6

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


Pre*_*raj 6

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


Hap*_*ppy 5

native由于功能或性能原因,Java方法为 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();
Run Code Online (Sandbox Code Playgroud)

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

  • 方法 13 availableProcessors:标记为 native 并且没有 Code 属性
  • 方法 14 freeMemory:标记为 native 并且没有 Code 属性
  • 方法 15 totalMemory:标记为 native 并且没有 Code 属性
  • 方法 16 maxMemory:标记为 native 并且没有 Code 属性
  • 方法 17 gc:标记为 native 并且没有 Code 属性

在此处输入图片说明

实际上的编码逻辑在对应的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  }
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

在此处输入图片说明

参考