2009-12-16 4 views
1

Considérez ceci:Pourquoi cette méthode n'est-elle pas choisie en fonction du type d'exécution de son objet?

class A { 
    int x =5; 
} 

class B extends A{ 
     int x =6; 
    } 
public class CovariantTest { 

    public A getObject() { 
     return new A(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     // TODO code application logic here 
     CovariantTest c1 = new SubCovariantTest(); 
     System.out.println(c1.getObject().x); 
    } 

} 

class SubCovariantTest extends CovariantTest { 
    public B getObject(){ 
     return new B(); 
    } 
} 

Pour autant que je sache, la machine virtuelle Java choisit une méthode basée sur le vrai type de son objet. Ici, le vrai type est SubCovariantTest, qui a défini une méthode de remplacement getObject.

Le programme imprime 5, au lieu de 6. Pourquoi?

Répondre

10

La méthode est en effet choisie par le type d'exécution de l'objet. Ce qui n'est pas choisi par le type d'exécution est l'entier le champx. Deux exemplaires de x existent pour l'objet B, un pour A.x et un pour B.x. Vous êtes statiquement en sélectionnant le champ de A classe, comme le type de l'objet de l'objet retourné par getObject est A. Ce fait peut être vérifié en ajoutant une méthode pour A et B:

class A { 
    public String print() { 
     return "A"; 
    } 
} 

class B extends A { 
    public String print() { 
     return "B"; 
    } 
} 

et changer l'expression de test:

System.out.println(c1.getObject().print()); 
+0

Vous avez fait un travail beaucoup mieux l'expliquer que moi ... C'est en fait une sorte de délicate à mot ... – LorenVS

1

À moins que je ne me trompe pas, les méthodes sont virtuelles en Java par défaut, vous remplacez la méthode correctement. Cependant, les champs (comme 'x') ne sont pas virtuels et ne peuvent pas être remplacés. Lorsque vous déclarez "int x" dans B, vous créez réellement une variable totalement nouvelle.

Polymorphisme ne va pas en vigueur pour les champs, donc quand vous essayez de récupérer x sur un objet de type A casted, vous obtiendrez 5, si l'objet est casté au type B, vous obtiendrez 6.

1

Lorsque les champs dans super et sous-classes ont les mêmes noms, il est appelé "masquage". Outre les problèmes mentionnés dans la question et la réponse, il y a d'autres aspects qui peuvent donner lieu à des problèmes subtils:

De http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html

Dans une classe, un champ qui a le même nom comme un champ dans la superclasse cache le champ de la superclasse, même si leurs types sont différents. Dans la sous-classe , le champ de la superclasse ne peut pas être référencé par son nom simple . Au lieu de cela, le champ doit être accédé par super, qui est couvert dans la section suivante. En général, nous ne recommandons pas de masquer les champs car cela rend le code difficile à lu.

Certains compilateurs mettre en garde contre les variables cacher

Questions connexes