遊んでいる間このパズル(Java キーワードクイズゲームです)、native
キーワードに出会いました。
Java の native キーワードは何に使用されますか?
ベストアンサー1
最小限の実行可能な例
メイン.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 パッケージ/ファイル名のアンダースコアは、_1
次のとおり C 関数名でエスケープする必要があります。アンダースコアを含む Android パッケージ名で JNI 関数を呼び出す
解釈
native
次のことが可能です:
- Javaから任意のアセンブリコードを使用して、コンパイルされた動的にロードされたライブラリ(ここではCで記述)を呼び出す
- 結果をJavaに返す
これは次の用途に使用できます:
- より優れた CPU アセンブリ命令を使用して、クリティカル セクションに高速なコードを書きます (CPU ポータブルではありません)
- 直接システムコールを行う(OS 移植不可)
ただし、その代償として携帯性は低下します。
C から Java を呼び出すことも可能ですが、まず C で JVM を作成する必要があります。C++ から Java 関数を呼び出すにはどうすればよいでしょうか?
同様のネイティブ拡張APIは、同じ理由で他の多くの「VM言語」にも存在します。たとえば、パイソン、Node.js、ルビー。
Android の NDK
このコンテキストでは概念はまったく同じですが、設定には Android ボイラープレートを使用する必要がある点が異なります。
公式 NDK リポジトリには、hello-jni アプリなどの「標準的な」例が含まれています。
- https://github.com/googlesamples/android-ndk/blob/4df5a2705e471a0818c6b2dbc26b8e315d89d307/hello-jni/app/src/main/java/com/example/hellojni/HelloJni.java#L39
- hello-jni のサンプルは、次の URL から入手できます。
unzip
Android O で NDK を使用する場合、の下にあるネイティブ コードに対応する.apk
プリコンパイル済みコードを確認できます。.so
lib/arm64-v8a/libnative-lib.so
TODO 確認: さらに、file /data/app/com.android.appname-*/oat/arm64/base.odex
は共有ライブラリであると述べており、これは ART 内の Java ファイルに対応する AOT プリコンパイル済み .dex であると思われます。以下も参照してください。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
これは、オブジェクトのネイティブメソッドを実装している可能性のあるCまたはC++ファイルを検索します。jdk/share/ネイティブ/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");
一連のマクロを展開した結果、これが定義ポイントであるという結論に達しました。