11

私はその振る舞いを知っていますが、なぜこれが起こるのか100%確信が持てません。
Javaにはインスタンス変数のポリモーフィズムがないことを理解しています。変数はコンパイラーによって静的に解決されます。
しかし、以下では私は何かについて混乱しています:

class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("My name is "+ name);  
   }  
}  

public class Dog extends Animal {   
   String name = "Dog";   

   public static void main(String[] args) {  
        Animal a = new Dog();  
        Dog d = new Dog();  
        System.out.println(a.name);//Line 1  
        a.display();//Line 2   
        d.display();//Line 3  
   }  
}  

(コンパイラによって解決された)の静的タイプであるため、その中Line 1に表示されることを理解しています。 私を混乱させるのは、なぜ表示されるのかということです。これは実行時の実際のオブジェクトであり、オーバーライドされていないため、メソッドは親クラスで検出されるため、メソッドの呼び出しが試行され ます。 私が得られないのは、操作される実際のオブジェクトがである場合に、メソッド内で親クラスのが使用される理由です。親の変数を隠しませんか?タイプが。であるため、静的に解決されているようには見えません。それはオブジェクトのメモリレイアウトの一部ではありませんか? 中のようですAnimala
Line 3My name is Animal
DogAnimal
namedisplayDognameDog
display親の変数のみが表示されます。なんで?

アップデート:

@Razvanと@LouisWassermanによる回答は役に立ちました。
これらの後に最後の質問が1つ
あります。両方のポイントは次のようです。@
Razyan
System.out.println("My name is "+ this.name); //<-- note the this
から
@Louisthisから。Animalthe implementation of display() is in the Animal class

これまでのところ大丈夫です。しかし、これらの点は、display()次のように変更し た場合の事実とどのように一致していますか。

class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("Current class is "+ this.getClass().getName());  
    System.out.println("My name is "+ name);  
   }  
}  

次に、次の結果が得られます。

 Dog d = new Dog();  
 d.display();  

現在のクラスは
です 私の名前は動物です

私はここで答えを理解した通りthisの中にあるdisplayだろうと期待していました。Animalそうではありません。なんで?

4

4 に答える 4

13

Dogクラスではオーバーライドしないため、を呼び出すとd.display()、が呼び出されます。Animal.display()

したがって、の架空の実装は次のDog.display()ようになります。

 public void display(){  
    super.display();
 }

そして、Animal.display()の実装は次のとおりです。

 public void display(){  
    System.out.println("My name is "+ this.name); //<-- note the this
 } 

このAnimal.display()メソッドは、オブジェクトの存在、Dogしたがってそのname変数の存在さえも認識していません。

于 2012-08-20T22:01:54.783 に答える
2

これは、それについて考えるより便利な方法かもしれません。変数が同じ名前を持っているという事実は、少しも重要ではありません。このコードは、まったく同じように動作します

class Animal{  
   String foo = "Animal";  
   public void display(){  
    System.out.println("My name is "+ foo);  
   }  
}  

public class Dog extends Animal {   
   String bar = "Dog";   

   public static void main(String[] args) {  
        Animal a = new Dog();  
        Dog d = new Dog();  
        System.out.println(a.foo);//Line 1  
        a.display();//Line 2   
        d.display();//Line 3  
   }
}

重要なのは、クラスname内のフィールドは、のフィールドDogから完全に完全に分離されているものとして扱われ、その点で、どのメソッドによって表示されるかということです。直接参照すると、それがであることがわかるだけなので、クラスのフィールドを使用します。nameAnimala.nameaAnimalnameAnimal

于 2012-08-20T22:12:53.113 に答える
2

ここでは、他のすべてのポイントを1つの回答にまとめて、手間をかけずに明確に把握できるようにします。

概念的には、コードは次のように考えることができます

class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("My name is "+ this.name);  
   }  
}  

public class Dog extends Animal {   
   String name = "Dog";  
   public void display(){  
    super.display();
 } 

   public static void main(String[] args) {  
        Animal a = new Dog();  
        Dog d = new Dog();  
        System.out.println(a.name);//Line 1  
        a.display();//Line 2   
        d.display();//Line 3  
   }  
} 

ここで犬のクラスでは、動物クラスの名前フィールドをシャドウイングしています。nameDogのインスタンスには、 1つはAnimal.name(値「Animal」を保持する継承から)、2つ目はDog.name(値「Dog」を保持する)という名前の2つのインスタンス変数があります。クラスにDog.name隠れます。Line-3では、display()メソッドが.Dogのインスタンスで呼び出されます。Dogはdisplay()メソッドをオーバーライドしないため、最終的にメソッドが呼び出されます。このメソッドでは、2つを参照し、その中に2つあり、1つは印刷されます(スーパークラスであることはクラスを認識しないため、 )Animal.nameDog
DogAnimalAnimal.display()thisDogDognameAnimalAnimalDogDog.name

于 2015-09-17T21:55:10.627 に答える
1

デバッグモードで実行された単純なJUnitテストは、Dogオブジェクトに実際に2つの「name」変数があることを示しています。さて、OPの最新のアップデートで尋ねられた質問に答えます:

 class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("Current class is "+ this.getClass().getName());  
    System.out.println("My name is "+ name);  
   }  
} 

Dog d = new Dog
d.display();

ここで、「d」には2つの変数が含まれています-> 1つは継承された変数で、もう1つはdogクラスで定義された変数で、どちらも同じ名前です。これで、Dogオブジェクトでdisplay()が呼び出されると、Animalクラスのdisplay()メソッドがオーバーライドされなかったため、JVMはAnimalクラスのdisplay()メソッドを実行します。

System.out.println("Current class is "+ this.getClass().getName());  

Dogは、メソッドが呼び出された実際のオブジェクトであるため、印刷されます。

System.out.println("My name is "+ name);  

前に述べたように、Dogのオブジェクトには両方の変数が含まれているため、「私の名前はAnimal」と出力されますが、Animal.display()メソッド内に入ると、スコープによって変数Animal.nameの値が選択されます。

于 2016-04-01T18:46:43.693 に答える