35

Java Object クラスを見ると、次のようなメソッドがいくつか見つかります。

public native int hashCode()
protected native Object clone()

これらのネイティブとは何ですか?これらのメソッドはどのように機能しますか?

4

5 に答える 5

19

他の回答で述べたように、ほとんどのネイティブ メソッドは JNI を使用して実装されています。

ただし、 などのパフォーマンス クリティカルなメソッドObject.hashCodeは通常、組み込み関数として実装されます。バイト コードがマシン コードにコンパイルされると、Java コンパイラはメソッド呼び出しを認識し、適切なコードを直接インライン化します。これは、単純な方法で JNI を使用するよりもはるかに高速であることは明らかです。

Object.hashCode多くの人は、メモリ内のオブジェクト表現のアドレスを返すと主張します。最新の実装では、オブジェクトは実際にメモリ内を移動します。代わりに、値を格納するためにオブジェクト ヘッダーの領域が使用されます。この値は、値が最初に要求された時点でメモリ アドレスから遅延して導出される場合があります。

于 2009-02-19T13:57:59.657 に答える
11

これらのネイティブとは何ですか?これらのメソッドはどのように機能しますか?

物事を明確にするための最小限の例:

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 でテスト済み。Oracle JDK 1.8.0_45 でも動作しました。

試してみるGitHub の例。

解釈:

次のことが可能になります。

  • Java からの任意のアセンブリ コードを使用して、コンパイル済みの動的に読み込まれたライブラリ (ここでは C で記述) を呼び出します。
  • 結果をJavaに戻す

これは次の目的で使用できます。

  • より優れた CPU アセンブリ命令 (CPU ポータブルではない) を使用して、クリティカル セクションに高速なコードを記述します。
  • 直接システムコールを行う (OS ポータブルではない)

移植性が低いというトレードオフがあります。

C から Java を呼び出すこともできますが、最初に C で JVM を作成する必要があります: C++ から Java 関数を呼び出すには?

OpenJDK 8 での例

Object#clonejdk8u60-b27 で定義されているfind を探してみましょう。

まず、次のことを見つけます。

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/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");

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

于 2015-06-04T06:02:58.573 に答える