Remplacer ou masquer Java - Confus


88

Je ne comprends pas en quoi le remplacement diffère du masquage en Java. Quelqu'un peut-il fournir plus de détails sur la différence entre ces derniers? J'ai lu le tutoriel Java, mais l'exemple de code m'a toujours laissé perplexe.

Pour être plus clair, je comprends bien la priorité. Mon problème est que je ne vois pas en quoi le masquage est différent, à l'exception du fait que l'un est au niveau de l'instance tandis que l'autre est au niveau de la classe.

En regardant le code du didacticiel Java:

public class Animal {
    public static void testClassMethod() {
        System.out.println("Class" + " method in Animal.");
    }
    public void testInstanceMethod() {
        System.out.println("Instance " + " method in Animal.");
    }
}

Ensuite, nous avons une sous-classe Cat:

public class Cat extends Animal {
    public static void testClassMethod() {
        System.out.println("The class method" + " in Cat.");
    }
    public void testInstanceMethod() {
        System.out.println("The instance method" + " in Cat.");
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        Animal myAnimal = myCat;
        Animal.testClassMethod();
        myAnimal.testInstanceMethod();
    }
}

Puis ils disent:

La sortie de ce programme est la suivante:

Méthode de classe en animal.

La méthode d'instance dans Cat.

Pour moi, le fait que l'appel d'une méthode de classe testClassMethod()directement à partir de la Animalclasse exécute la méthode dans la Animalclasse est assez évident, rien de spécial ici. Ensuite, ils appellent testInstanceMethod()from une référence à myCat, donc encore une fois assez évident que la méthode exécutée est alors celle de l'instance deCat .

D'après ce que je vois, le masquage d'appel se comporte comme un dépassement, alors pourquoi faire cette distinction? Si j'exécute ce code en utilisant les classes ci-dessus:

Cat.testClassMethod();

J'obtiendrai: La méthode de classe dans Cat. Mais si je supprime le testClassMethod()de Cat, alors j'obtiendrai: La méthode de classe dans Animal.

Ce qui me montre que l'écriture d'une méthode statique, avec la même signature que dans le parent, dans une sous-classe fait à peu près un remplacement.

J'espère que je clarifie mes points de confusion et que quelqu'un puisse faire la lumière. Merci d'avance!


Réponses:


103

Le remplacement prend essentiellement en charge la liaison tardive. Par conséquent, il est décidé au moment de l'exécution quelle méthode sera appelée. C'est pour les méthodes non statiques.

Le masquage concerne tous les autres membres (méthodes statiques, membres d'instance, membres statiques). Il est basé sur la liaison anticipée. Plus clairement, la méthode ou le membre à appeler ou à utiliser est décidé lors de la compilation.

Dans votre exemple, le premier appel Animal.testClassMethod()est un appel à une staticméthode, il est donc assez sûr de savoir quelle méthode va être appelée.

Dans le deuxième appel, myAnimal.testInstanceMethod()vous appelez une méthode non statique. C'est ce que vous appelez le polymorphisme d'exécution. Il n'est pas décidé avant l'exécution de la méthode à appeler.

Pour plus de précisions, lisez Overriding Vs Hiding .


3
Merci pour la réponse rapide, cela clarifie les choses! J'ai remarqué que dans l'exemple JavaRanch, ils utilisaient la variable pour appeler la méthode de classe au lieu d'utiliser la classe directement, ce qui la rend plus facile à comprendre. Je suppose que dans le didacticiel Java, ils ont utilisé la classe directement car utiliser une instance pour appeler une méthode statique n'est probablement pas une bonne pratique, mais ils auraient dû utiliser myAnimal.testClassMethod () au lieu de Animal.testClassMethod () .
Lostlinkpr

+1 pour pouvoir le mettre en mots correctement, plutôt que par exemple! :)
WhyNotHugo

@Kazekage Gaara Y a-t-il une différence entre la surcharge et la dissimulation?
gstackoverflow

1
Je suis bien sûr d'accord avec la réponse, mais qu'en est-il private methods? Ils ne peuvent pas l'être overriddenpuisque la sous-classe ne connaît pas leur existence. Par conséquent, ils pourraient l'être à la hiddenplace.
Paschalis

Excellente réponse! Bien que vous puissiez ajouter l'exemple à coderanch par souci d'exhaustivité :)
Shubham Mittal

19

Les méthodes statiques sont masquées, les méthodes non statiques sont remplacées. La différence est notable lorsque les appels ne sont pas qualifiés de "quelque chose ()" vs "this.something ()".

Je n'arrive pas vraiment à le mettre sur des mots, alors voici un exemple:

public class Animal {

    public static void something() {
        System.out.println("animal.something");
    }

    public void eat() {
        System.out.println("animal.eat");
    }

    public Animal() {
        // This will always call Animal.something(), since it can't be overriden, because it is static.
        something();
        // This will call the eat() defined in overriding classes.
        eat();
    }

}


public class Dog extends Animal {

    public static void something() {
        // This method merely hides Animal.something(), making it uncallable, but does not override it, or alter calls to it in any way.
        System.out.println("dog.something");
    }

    public void eat() {
        // This method overrides eat(), and will affect calls to eat()
        System.out.println("dog.eat");
    }

    public Dog() {
        super();
    }

    public static void main(String[] args) {
        new Dog();
    }

}

PRODUCTION:

animal.something
dog.eat

1
ok, alors que se passerait-il si j'appelais `dog husky = new dog (); ' et appelez husky.Animal();-le imprimer animal.quelque chose ou chien.quelque chose ? Je suppose que c'est FAUX de dire ** que ** Cela appellera toujours Animal.something ()
amarnath harish

@amarnathharish Vous ne pouvez pas faire .Animal(), rappelez Animal()- vous est un constructeur.
Dude156

Et comme clarification supplémentaire pour quiconque se demande, la raison pour laquelle l' Animal's something()in Animal() always call something()est parce qu'un appel à une méthode statique est résolu au moment de la compilation plutôt qu'au moment de l'exécution. Cela signifie que l'appel de méthode statique Animal()est toujours appelant implicitement Animal.something(). C'est assez intuitif si vous y réfléchissez: un appel à une méthode statique doit être précédé d'un nom de classe (ie className.staticMethodName()) sauf si l'appel est dans la même classe.
Dude156

14

C'est la différence entre les remplacements et le masquage,

  1. Si la méthode de la classe parent et la classe enfant sont toutes les deux une méthode d'instance, elle a appelé des substitutions.
  2. Si les deux méthodes de la classe parent et de la classe enfant sont des méthodes statiques, cela s'appelle le masquage.
  3. Une méthode ne peut pas être statique dans le parent et en tant qu'instance dans l'enfant. et vice versa.

entrez la description de l'image ici


3
Vous avez coupé et collé ce tableau directement à partir du didacticiel que l'OP a déclaré ne pas l'aider à comprendre.
Wolfcastle

Le tableau indique très clairement que dans les exemples, tous les cas n'ont pas été considérés.
tutak

3

Si je comprends bien votre question, la réponse est "vous l'emportez déjà".

"Ce qui me montre qu'écrire une méthode statique, avec le même nom que dans le parent, dans une sous-classe fait à peu près un remplacement."

Si vous écrivez une méthode dans une sous-classe avec exactement le même nom qu'une méthode dans une superclasse, elle remplacera la méthode de la superclasse. L'annotation @Override n'est pas requise pour remplacer une méthode. Cela rend cependant votre code plus lisible et force le compilateur à vérifier que vous remplacez réellement une méthode (et que vous n'avez pas mal orthographié la méthode de la sous-classe par exemple).


1
Cette réponse ne parvient pas à aborder l'instance par rapport aux méthodes statiques en ce qui concerne le remplacement / le masquage.
Paul Bellora

3

Le remplacement se produit uniquement avec les méthodes d'instance. Lorsque le type de la variable de référence est Animal et que l'objet est Cat, la méthode d'instance est appelée à partir de Cat (ceci est prioritaire). Pour le même objet acat, la méthode de classe Animal est utilisée.

public static void main(String[] args) {
    Animal acat = new Cat();
    acat.testInstanceMethod();
    acat.testClassMethod();

}

La sortie est:

The instance method in Cat.
Class method in Animal.

2
public class First {

    public void Overriding(int i) {  /* will be overridden in class Second */ }

    public static void Hiding(int i) {  /* will be hidden in class Second
                                           because it's static */ }
}


public class Second extends First {

    public void Overriding(int i) {  /* overridden here */  }

    public static void Hiding(int i) {  /* hides method in class First
                                           because it's static */ } 
}

La règle de mémorisation est simple: une méthode dans une classe d'extension ne peut pas changer static en void et ne peut pas changer void en static. Cela provoquera une erreur de compilation.

Mais si void Nameest changé en void Namec'est Overriding.

Et si static Nameest changé en static Namec'est se cacher. (La méthode statique de la sous-classe ainsi que celle de la superclasse peuvent être appelées, selon le type de la référence utilisée pour appeler la méthode.)


1

Dans cet extrait de code, j'utilise un modificateur d'accès «privé» au lieu de «statique» pour vous montrer la différence entre les méthodes de masquage et les méthodes de substitution.

class Animal {
// Use 'static' or 'private' access modifiers to see how method hiding work.
private void testInstancePrivateMethod(String source) {
    System.out.println("\tAnimal: instance Private method calling from "+source);
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Private method.");
    testInstancePrivateMethod( Animal.class.getSimpleName() );
}

// Use default, 'protected' or 'public' access modifiers to see  how method overriding work.
protected void testInstanceProtectedMethod(String source) {
    System.out.println("\tAnimal: instance Protected method calling from "+source);
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("\tAnimal: instance Public method with using of Protected method.");
    testInstanceProtectedMethod( Animal.class.getSimpleName() );
  } 
}  


public class Cat extends Animal {
private void testInstancePrivateMethod(String source) {
    System.out.println("Cat: instance Private method calling from " + source );
}
public void testInstanceMethodUsingPrivateMethodInside() {
    System.out.println("Cat: instance Public method with using of Private method.");
    testInstancePrivateMethod( Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingPrivateMethodInside();
}

protected void testInstanceProtectedMethod(String source) {
    System.out.println("Cat: instance Protected method calling from "+ source );
}
public void testInstanceMethodUsingProtectedMethodInside() {
    System.out.println("Cat: instance Public method with using of Protected method.");
    testInstanceProtectedMethod(Cat.class.getSimpleName());
    System.out.println("Cat: and calling parent after:");
    super.testInstanceMethodUsingProtectedMethodInside();
}

public static void main(String[] args) {
    Cat myCat = new Cat();
    System.out.println("----- Method hiding -------");
    myCat.testInstanceMethodUsingPrivateMethodInside();
    System.out.println("\n----- Method overriding -------");
    myCat.testInstanceMethodUsingProtectedMethodInside();
}
}

Production:

----- Method hiding -------
Cat: instance Public method with using of Private method.
Cat: instance Private method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Private method.
   Animal: instance Private method calling from Animal

----- Method overriding -------
Cat: instance Public method with using of Protected method.
Cat: instance Protected method calling from Cat
Cat: and calling parent after:
   Animal: instance Public method with using of Protected method.
Cat: instance Protected method calling from Animal

Je me demande pourquoi il n'a pas obtenu les votes positifs .. réponse très appréciée.
amarnath harish

0

Basé sur mes récentes études Java

  • méthode remplacement de , lorsque la sous-classe a la même méthode avec la même signature dans la sous-classe.
  • procédé cacher , lorsque la sous - classe ont le même nom de méthode, mais paramètre différent. Dans ce cas, vous ne remplacez pas la méthode parente, mais la masquez.

Exemple du livre OCP Java 7, pages 70-71:

public class Point {
  private int xPos, yPos;
  public Point(int x, int y) {
        xPos = x;
        yPos = y;
  }

  public boolean equals(Point other){
  .... sexy code here ...... 
  }

  public static void main(String []args) {
   Point p1 = new Point(10, 20);
   Point p2 = new Point(50, 100);
   Point p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //point's class equals method get invoked
  }
}

mais si nous écrivons le main suivant:

  public static void main(String []args) {
   Object p1 = new Point(10, 20);
   Object p2 = new Point(50, 100);
   Object p3 = new Point(10, 20);
   System.out.println("p1 equals p2 is " + p1.equals(p2));
   System.out.println("p1 equals p3 is " + p1.equals(p3));
   //Object's class equals method get invoked
  }

Dans la deuxième main, nous utilisons la classe Object comme type statique, donc lorsque nous appelons la méthode equal dans l'objet Point, nous attendons qu'une classe Point arrive en tant que paramètre, mais Object coming. Ainsi, la méthode de la classe Object est exécutée, car nous avons un égal (Object o). Dans ce cas, la classe de Point equals ne remplace pas, mais masque la méthode equals de la classe Object .


0
public class Parent {

  public static void show(){
    System.out.println("Parent");
  }
}

public class Child extends Parent{

  public static void show(){
    System.out.println("Child");
  }
}

public class Main {

public static void main(String[] args) {
    Parent parent=new Child();
    parent.show(); // it will call parent show method
  }
}

// We can call static method by reference ( as shown above) or by using class name (Parent.show())

0

La page de didacticiel Java liée explique le concept de remplacement et de masquage

Une méthode d'instance dans une sous-classe avec la même signature (nom, plus le numéro et le type de ses paramètres) et le type de retour en tant que méthode d'instance dans la superclasse remplace la méthode de la superclasse.

Si une sous-classe définit une méthode statique avec la même signature qu'une méthode statique de la superclasse, alors la méthode de la sous-classe masque celle de la superclasse.

La distinction entre masquer une méthode statique et remplacer une méthode d'instance a des implications importantes:

  1. La version de la méthode d'instance remplacée qui est appelée est celle de la sous-classe.
  2. La version de la méthode statique masquée qui est appelée dépend du fait qu'elle soit invoquée à partir de la superclasse ou de la sous-classe.

Revenons à votre exemple:

Animal myAnimal = myCat;

 /* invokes static method on Animal, expected. */
 Animal.testClassMethod(); 

 /* invokes child class instance method (non-static - it's overriding) */
 myAnimal.testInstanceMethod();

La déclaration ci-dessus ne montre pas encore de se cacher.

Modifiez maintenant le code comme ci-dessous pour obtenir une sortie différente:

  Animal myAnimal = myCat;
  
  /* Even though myAnimal is Cat, Animal class method is invoked instead of Cat method*/
  myAnimal.testClassMethod();
  
  /* invokes child class instance method (non-static - it's overriding) */
  myAnimal.testInstanceMethod();

J'essaie de comprendre ce que signifie le mot se cacher. Qu'est-ce qui cache quoi? La méthode statique de la classe Parent est-elle masquée car (la moins attendue) elle est appelée? Ou la méthode statique de la classe Child est-elle masquée, car elle n'est pas appelée?
scorpion

0

En plus des exemples répertoriés ci-dessus, voici un petit exemple de code pour clarifier la distinction entre le masquage et le remplacement:

public class Parent {

    // to be hidden (static)
    public static String toBeHidden() {
        return "Parent";
    }

    // to be overridden (non-static)
    public String toBeOverridden() {
        return "Parent";
    }

    public void printParent() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Child extends Parent {

    public static String toBeHidden() {
        return "Child";
    }

    public String toBeOverridden() {
        return "Child";
    }

    public void printChild() {
        System.out.println("to be hidden: " + toBeHidden());
        System.out.println("to be overridden: " + toBeOverridden());
    }
}

public class Main {

    public static void main(String[] args) {
        Child child = new Child();
        child.printParent();
        child.printChild();
    }
}

L'appel des child.printParent()sorties:
à masquer: Parent
à remplacer: Enfant

L'appel des child.printChild()sorties:
à masquer: Enfant
à remplacer: Enfant

Comme nous pouvons le voir à partir des sorties ci-dessus (en particulier les sorties marquées en gras), le masquage de méthode se comporte différemment du remplacement.

Java autorise à la fois le masquage et le remplacement des méthodes uniquement. La même règle ne s'applique pas aux variables. Le remplacement des variables n'est pas autorisé, les variables ne peuvent donc être masquées (aucune différence entre les variables statiques ou non statiques). L'exemple ci-dessous montre comment la méthode getName()est remplacée et la variable nameest masquée:

public class Main {

    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.name); // prints Parent (since hiding)
        System.out.println(p.getName()); // prints Child (since overriding)
    }
}

class Parent {
    String name = "Parent";

    String getName() {
        return name;
    }
}

class Child extends Parent {
    String name = "Child";

    String getName() {
        return name;
    }
}

0

Au moment de l'exécution, la version enfant d'une méthode remplacée est toujours exécutée pour une instance, que l'appel de méthode soit défini dans une méthode de classe parent ou enfant. De cette manière, la méthode parent n'est jamais utilisée sauf si un appel explicite à la méthode parent est référencé, en utilisant la syntaxe ParentClassName.method (). Alternativement, à l'exécution, la version parente d'une méthode masquée est toujours exécutée si l'appel à la méthode est défini dans la classe parente.


0

Dans le remplacement de méthode, la résolution de méthode est effectuée par la JVM sur la base de l'objet d'exécution. Alors que dans le masquage de méthode, la résolution de méthode est effectuée par le compilateur sur la base de référence. Donc,

Si le code aurait été écrit comme,

public static void main(String[] args) {
        Animal myCat = new Cat();        
        myCat.testClassMethod();        
    }

Le résultat serait comme ci-dessous:
Méthode de classe dans Animal.


0

Il est appelé masquage car le compilateur masque l'implémentation de la méthode de super classe, lorsque la sous-classe a la même méthode statique.

Le compilateur n'a pas de visibilité restreinte pour les méthodes surchargées et ce n'est que pendant l'exécution qu'il décide laquelle est utilisée.


0

Voici la différence entre le remplacement et le masquage:

Animal a = nouveau chat ();

a.testClassMethod () appellera la méthode dans la classe parent car il s'agit d'un exemple de masquage de méthode. La méthode à appeler est déterminée par le type de la variable de référence et décidée au moment de la compilation.

a.testInstanceMethod () appellera la méthode dans la classe enfant car il s'agit d'un exemple de substitution de méthode. La méthode à appeler est déterminée par l'objet qui est utilisé pour appeler la méthode lors de l'exécution.


-1

Comment le masquage de méthode statique se produit-il en Java? La classe de chat étend la classe animale. Donc, dans la classe Cat aura les deux méthodes statiques (je veux dire la méthode statique de la classe enfant et la méthode statique de la classe parent) Mais comment la JVM cache la méthode statique Parent? Comment ça se passe dans Heap and Stack?


Ce n'est pas une réponse. C'est le prolongement de la question posée. Il peut s'agir d'une question distincte elle-même ou d'une partie des commentaires sur la question.
Sri9911
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.