4

タイトルが間違っていたらすみません。Test と TestChild1 の 2 つのクラスがあり、TestChild1 は Test から継承されます。どちらのクラスにも「a」という名前の変数があります。サブクラスオブジェクトでインスタンス化されたスーパークラス変数を介して変数「a」にアクセスしようとすると、サブクラスではなくスーパークラスで初期化された値が返されます。以下は、疑問を提起したコードです

class Test {
    public int a = 10;
}

class TestChild1 extends Test {
    public int a = 20;
}

class Main {
    public static void main(String args[]) {
        Test test = new TestChild1();
        System.out.println(test.a); // results in 10
    }
}

この行動の理由を教えてください。前もって感謝します....

4

5 に答える 5

9

Java 設計者は、メソッドをポリモーフィック (したがってオーバーライド可能) にすることを決定しましたが、フィールドは作成しませんでした。

オブジェクトからフィールドを参照すると、宣言された変数の型 (この場合は )に基づいて、使用するフィールドがコンパイラによって決定されます。Test

メソッドを参照する場合、JVM は、実行時に、オブジェクトの実際の具象型 (この場合は )に基づいて呼び出すメソッドを選択しますTestChild

オブジェクト指向は状態のカプセル化がすべてであるため、とにかくフィールドを外部に公開することはほとんどありません。

于 2013-07-07T09:40:35.980 に答える
2

クラス TestChild1 には、同じ名前の 2 つの変数があります。Test を介してそれらにアクセスすると、最初のものを取得し、TestChild1 から 2 番目のものを取得します。

期待どおりの結果を得るには、派生クラスで a を宣言しないでください。代わりに、派生クラスのコストラクタで初期化する必要があります。

于 2013-07-07T09:41:24.100 に答える
1

Testサブクラスではなく、オブジェクトを として宣言しました。コンパイル時に、10 を持つ基本クラスを参照することを意味します。

于 2013-07-07T09:45:39.347 に答える
0

JB Nizetはすでにすべてを述べていますが、理解を深めるために次のコードを追加します。

class Test {
    private int a = 10;

    public int getA() {
        return a;
    }
}

class TestChild1 extends Test {
    private int a = 20;

    public int getA() {
        return a;
    }
}

class Main {
    public static void main(String args[]) {
        Test test = new TestChild1();
        System.out.println(test.getA()); // results in 20
    }
}

したがって、フィールドをカプセル化すると、期待どおりの動作が得られます。

于 2013-07-07T10:05:34.447 に答える
0

動作はフィールドではなくメソッドに関連付けられているためです。

そのため、フィールドには静的バインディングがあります (この場合、 test は typeTestであるため、 value of にaは値 10 が割り当てられます)。一方、メソッドには動的バインディングがあります。

変数はクラスaの動作を定義しないため、Testインスタンスごとではなく、型ごとに値が割り当てられます。

于 2013-07-07T09:45:13.220 に答える