3

Web で検索した後、インスタンス変数が Java メモリ モデル内の正確な場所についての適切で包括的な答えはまだ見つかりませんでした。たとえば、次のコードがあります (変数のシャドウ宣言を使用):

class A {
    int var = 1;
    void m() {
        System.out.println("\'m()\' is called from class A");
    }
}

class B extends A {
    int var = 5;
    void m() {
        System.out.println("\'m()\' is called from class B");
    }
}

public class Class1 {
    public static void main(String args[]) {
        A aref = new B();
        aref.m();
        String s = (aref.var)==1?"A":"B";
        System.out.println("\'var\' is called from class " + s);
    }
}

このコードの出力は次のとおりです。

'm()' is called from class B
'var' is called from class A

問題は、Java で継承がどのように機能するかではなく、Java メモリ モデルのどこにこのインスタンス変数が存在するかということです。あなたの答えを主張してください。

ありがとう

4

2 に答える 2

4

オブジェクトはヒープ内に保持されますが、すべての変数を組み合わせたサイズ + 仮想メソッド テーブル (VMT) とオブジェクトのプロトタイプの場所 (JVM 実装によってはそれ以上) を格納するための余分なバイトに等しい 1 つのメモリ ブロックとして保持されます。 .

したがって、サンプル オブジェクトは (32 ビット) メモリでは次のようになります (ポインター値は表示用です)。

[0000] 0154  // pointer to prototype
[0004] 3625  // pointer to virtual method table
[0008] 0001  // int var

上記の例では、メンバーにアクセスしていないため、JVM が行うことは、そのプロトタイプの VMT を見つけ、そこに書き留められた関数アドレスにジャンプして実行することだけです。

コードが実際にオプティマイザを通過した場合var = 1、結果のアセンブリ コードはこの「var」のことを認識せず、代わりに直接メモリ アクセスで動作します。このようなもの:

set [4924 + 8], 1 

4924 はインスタンスのメモリ ロケーションで、+ 8 は変数へのオフセットですvar。これは (人間が読めるように作成された)アセンブリであり、バイトコードではないことに注意してください。基本的には、JIT が完了すると何が残るかということです。

両方のオブジェクトが同じサイズであるため、A を B に「アップキャスト」することさえ可能です。それが機能しない唯一の理由は、Java がそのような安全でない操作を禁止しているためです。C++ のような他の安全性の低い言語では、それを簡単に行うことができ、おそらく問題なく実行できます。

于 2013-11-14T16:47:30.777 に答える
1

継承する場合、変数はメソッドとは異なります。メソッド m() は、A を拡張するときに B クラスで上書きされます。ただし、B は親クラスのローカル変数をオーバーライドすることはできません。これは、それらに対する権限がないためです。

于 2013-11-14T16:23:22.977 に答える