Answers:
所述native
关键字被应用于方法,以指示该方法是在本机代码使用JNI(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包/文件名中的下划线必须使用_1
C函数名进行转义,如下所述:在包含下划线的Android包名中调用JNI函数
解释
native
允许您:
这可以用来:
以降低便携性为代价。
也可以从C调用Java,但是必须首先在C中创建JVM:如何从C ++调用Java函数?
Android NDK
除了必须使用Android样板进行设置外,该概念在此情况下完全相同。
官方的NDK存储库包含“规范”示例,例如hello-jni应用程序:
在您unzip
的.apk
使用NDK Android上的O,你可以看到预编译.so
对应下的本地代码lib/arm64-v8a/libnative-lib.so
。
TODO确认:此外,file /data/app/com.android.appname-*/oat/arm64/base.odex
表示这是一个共享库,我认为这是AART预编译的.dex,它对应于ART中的Java文件,另请参见:什么是Android中的ODEX文件?那么也许Java实际上也可以通过native
接口运行?
OpenJDK 8中的示例
让我们找到Object#clone
jdk8u60-b27中定义的位置。
我们将得出结论,它是通过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");
扩展了一堆宏之后,我们得出的结论是这是定义点。
static
native
Java方法,C ++函数的第二个参数的类型为jclass
而不是jobject
。
它标记了一种方法,它将以其他语言而不是Java来实现。它与JNI(Java本机接口)一起使用。
过去曾使用本机方法来编写性能至关重要的部分,但是随着Java变得越来越快,这种方法现在已不那么普遍了。当前需要本机方法
您需要从Java调用用其他语言编写的库。
您需要访问只能从其他语言(通常为C)访问的系统或硬件资源。实际上,许多与真实计算机交互的系统功能(例如磁盘和网络IO)只能这样做,因为它们调用了本机代码。
另请参见 Java本机接口规范
currentTimeMillis
是JDK的一部分,并带有注解,native
因为实现是在JDK源代码本身中进行的。实现不太可能使用汇编语言。它可能会调用JVM在其上运行的操作系统的API方法。例如,在Windows上,它可能GetSystemTime
在kernel32.dll中调用DLL方法。在另一个操作系统上,它将具有不同的实现。但是,当您使用native
要编写的方法(与JDK方法相对)时,则必须使用JNI提供实现。
currentTimeMillis
被标记为本机,java.lang.System
因此它使用JNI,不是吗?
实现本机代码的函数被声明为本机。
Java本机接口(JNI)是一个编程框架,使在Java虚拟机(JVM)中运行的Java代码能够调用本机应用程序(特定于硬件和操作系统平台的程序)和编写的库,并由它们进行调用。其他语言,例如C,C ++和汇编语言。
native是java中的关键字,它用于使未实现的结构(方法)像抽象的一样,但是它将依赖于平台(例如本机代码)并从本机堆栈而不是java堆栈执行。
native
由于功能或性能原因,Java 方法为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_NATIVE
(0x0100
)标记,并且这些方法不包含Code属性,这意味着这些方法在Runtime.class
文件中没有任何实际的编码逻辑:
availableProcessors
:标记为本机且没有Code属性freeMemory
:标记为本机且没有Code属性totalMemory
:标记为本机且没有Code属性maxMemory
:标记为本机且没有Code属性gc
:标记为本机且没有代码属性实际上,编码逻辑位于相应的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
:
参考