Javaのネイティブキーワードとは何ですか? 質問する

Javaのネイティブキーワードとは何ですか? 質問する

遊んでいる間このパズル(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 アプリなどの「標準的な」例が含まれています。

unzipAndroid O で NDK を使用する場合、の下にあるネイティブ コードに対応する.apkプリコンパイル済みコードを確認できます。.solib/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#clonejdk8u60-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");

一連のマクロを展開した結果、これが定義ポイントであるという結論に達しました。

おすすめ記事