web-dev-qa-db-fra.com

Remplacement de variables membres en Java

J'étudie les fonctions de membre dominantes en Java et je pense à expérimenter avec des variables de membre dominantes.

Alors, j'ai défini les classes

public class A{
    public int intVal = 1;
    public void identifyClass()
    {
        System.out.println("I am class A");
    }
}

public class B extends A
{
    public int intVal = 2;
    public void identifyClass()
    {
        System.out.println("I am class B");
    }
}

public class mainClass
{
    public static void main(String [] args)
    {
        A a = new A();
        B b = new B();
        A aRef;
        aRef = a;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
        aRef = b;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
    }
}

La sortie est:

1
I am class A
1
I am class B

Je n'arrive pas à comprendre pourquoi, quand aRef est défini sur b, intVal est-il toujours de classe A?

51
Kalyan Raghu

Lorsque vous créez une variable du même nom dans une sous-classe, cela s'appelle hiding. La sous-classe résultante aura désormais les propriétés les deux. Vous pouvez accéder à celui de la superclasse avec super.var ou ((SuperClass)this).var. Les variables ne doivent même pas être du même type; ce ne sont que deux variables partageant un nom, un peu comme deux méthodes surchargées.

67
Marko Topolnik

Les variables ne sont pas polymorphes en Java; ils ne se substituent pas les uns aux autres.

51

Les variables sont résolues au moment de la compilation, les méthodes au moment de l'exécution. ARef est de type A, par conséquent aRef.Intvalue est résolu à la compilation au moment de la compilation.

11
Rostislav Matl

Il n'y a pas de polymorphisme pour les champs en Java.  

La décision Variables se produit à la compilation, donc toujours Les variables de la classe de base (les variables héritées de l’enfant) seront utilisées.

Ainsi, chaque fois que survient la surchauffe, rappelez-vous toujours

1) Les variables de la classe de base seront accessibles.

2) Les méthodes Sub Class (les méthodes substituées si le remplacement est passé, les autres méthodes héritées telles qu'elles sont du parent) seront appelées.

10
Ankur Singhal

Concept OverRiding en Java Les fonctions remplaceront en fonction du type d'objet et les variables accédées en fonction du type de référence. 

  1. Fonction de substitution: dans ce cas, supposons qu'une classe parent et une classe enfant aient le même nom de fonction avec sa propre définition. Mais la fonction qui l'exécutera dépend du type d'objet et non du type de référence au moment de l'exécution.

Par exemple:

Parent parent=new Child();
parent.behaviour();

Ici parent est une référence de classe Parent mais contient un objet de classe enfant, c'est pourquoi la fonction de classe enfant sera appelée dans ce cas.

Child child=new Child();
child.behaviour();

Ici child contient un objet de classe enfant, ainsi la fonction de classe enfant sera appelée.

Parent parent=new Parent();
parent.behaviour();

Ici, parent contient l'objet de la classe parent, ainsi la fonction de la classe parent sera appelée.

  1. Remplacer la variable: Java prend en charge les variables surchargées. Mais en réalité, il s’agit de deux variables différentes portant le même nom, l’une dans la classe parent et l’autre dans la classe enfant. Et les deux variables peuvent être du même type de données ou différentes.

Lorsque vous essayez d'accéder à la variable, cela dépend de l'objet de type référence, pas du type d'objet.

Par exemple:

Parent parent=new Child();
System.out.println(parent.state);

Le type de référence est Parent. La variable de classe Parent est accessible, et non la variable de classe Child.

Child child=new Child();
System.out.println(child.state);

Ici, le type de référence est Child. La variable de classe Child n'est donc pas utilisée, mais la variable de classe Parent.

Parent parent=new Parent();
System.out.println(parent.state);

Ici, le type de référence est Parent. La variable de classe Parent est accessible.

4
Aman Goyal

A partir de JLS Java SE 7 Edition §15.11.1:

Ce manque de recherche dynamique pour les accès sur le terrain permet aux programmes d'être exécutés efficacement avec des implémentations simples. La capacité de liaison et de substitution tardives est disponible, mais uniquement lorsque des méthodes d'instance sont utilisées.

Les réponses d'Oliver Charlesworth et de Marko Topolnik sont correctes, je souhaiterais en dire un peu plus sur la partie {pourquoi} de la question:

En Java membres de la classe are accédé en fonction du type de la référence et non du type de l'objet réel. Pour la même raison, si vous aviez une someOtherMethodInB() dans la classe B, vous ne pourrez pas y accéder à partir de aRef après l'exécution de aRef = b. Les identifiants (c'est-à-dire les noms de classe, de variable, etc.) sont résolus au moment de la compilation et le compilateur s'appuie donc sur le type de référence pour le faire.

Dans votre exemple, lorsque vous exécutez System.out.println(aRef.intVal);, il affiche la valeur intVal définie dans A car il s'agit du type de référence que vous utilisez pour y accéder. Le compilateur voit que aRef est de type A et que c'est la intVal à laquelle il aura accès. N'oubliez pas que vous avez les deux _ champs dans les instances de B. JLS a également un exemple similaire au vôtre, "15.11.1-1. Liaison statique pour l'accès aux champs" si vous voulez y jeter un coup d'œil.

Mais pourquoi les méthodes se comportent-elles différemment? La réponse est que pour les méthodes, Java utilise late binding. Cela signifie qu’au moment de la compilation, il trouve la méthode la plus appropriée pour recherche pendant l’exécution. La recherche implique le cas où la méthode est remplacée dans une classe.

3

Ceci est appelé masquage de variable . Lorsque vous affectez aRef = b;, aRef a deux intVal, 1 est nommé intVal, un autre est masqué sous A.intVal (voir la capture d'écran du débogueur), car votre variable est de type class A, même lorsque vous imprimez simplement intVal. Java récupère intelligemment A.intVal.

Réponse 1 : Un moyen d'accéder à la variable intVal de la classe enfant est System.out.println((B)aRef.intVal);

Réponse 2 : Une autre façon de le faire est Java Reflection car lorsque vous utilisez une réflexion, Java ne peut pas lire intelligemment le code A.intVal caché en fonction du type de classe, il doit saisir le nom de la variable sous forme de chaîne -

import Java.lang.reflect.Field;

class A{
    public int intVal = 1;
    public void identifyClass()
    {
        System.out.println("I am class A");
    }
}

class B extends A
{
    public int intVal = 2;
    public void identifyClass()
    {
        System.out.println("I am class B");
    }
}

public class Main
{
    public static void main(String [] args) throws Exception
    {
        A a = new A();
        B b = new B();
        A aRef;
        aRef = a;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
        aRef = b;
        Field xField = aRef.getClass().getField("intVal");
        System.out.println(xField.get(aRef));
        aRef.identifyClass();
    }
}

Sortie -

1
I am class A
2
I am class B

 enter image description here 

1
sapy

J'espère que cela peut aider

public class B extends A {
//  public int intVal = 2;

    public B() {
        super();
        super.intVal = 2;
    }

    public void identifyClass() {
        System.out.println("I am class B");
    }
}
0

Selon les spécifications Java, les variables d'instance ne sont pas écrasées d'une super classe par une sous-classe lorsqu'elle est étendue.

Par conséquent, la variable de la sous-classe uniquement peut être vue comme une variable partageant le même nom.

De même, lorsque le constructeur de A est appelé lors de la création de l'instance de B, la variable (intVal) est initialisée et donc la sortie.

0
Siddharth Singh

J'espère que tu as la réponse. Sinon, vous pouvez essayer de voir en mode débogage. la sous-classe B a accès à l'intVal. Ils ne sont pas polymorphes et ne sont donc pas surchargés.

Si vous utilisez la référence de B, vous obtiendrez son intVal. Si vous utilisez la référence de A, vous obtiendrez son intVal. C'est si simple.

0
dharam