web-dev-qa-db-fra.com

Ignorer vs cacher Java - Confus

Je suis confus sur la différence entre le remplacement et la dissimulation en Java. Quelqu'un peut-il fournir plus de détails sur la manière dont ils diffèrent? J'ai lu le Java Tutorial mais l'exemple de code m'a laissé confus.

Pour être plus clair, je comprends bien passer outre. Mon problème est que je ne vois pas que cacher soit une différence, sauf que l'une se situe au niveau de l'instance et l'autre au niveau de la classe.

En regardant le code du tutoriel 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 un chat de la sous-classe:

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 d'appeler une méthode de classe testClassMethod () directement à partir de la classe Animal, exécute la méthode dans la classe Animal est assez évident, rien de spécial là-bas. Ensuite, ils appellent la méthode testInstanceMethod () à partir d'une référence à myCat. Il est donc de nouveau assez évident que la méthode exécutée à ce moment-là est celle de l'instance de Cat.

D'après ce que je vois, l'appel caché se comporte comme une priorité, alors pourquoi faire cette distinction? Si je lance ce code en utilisant les classes ci-dessus:

Cat.testClassMethod();

Je vais avoir: La méthode de classe dans Cat. Mais si je supprime le testClassMethod () de Cat, 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 effectue à peu près un remplacement.

Si tout va bien, je précise clairement où je suis confus et que quelqu'un peut nous éclairer un peu. Merci d'avance!

64
Lostlinkpr

Le sur-supportage supporte fondamentalement les liaisons tardives. Par conséquent, la méthode qui sera appelée est déterminée au moment de l'exécution. Elle s'applique aux méthodes non statiques . Le masquage s'applique à 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é au moment de la compilation.

Dans votre exemple, le premier appel, Animal.testClassMethod() est un appel à une méthode static; il est donc à peu près sûr de la méthode à appeler.

Dans le deuxième appel, myAnimal.testInstanceMethod(), il appelle une méthode non statique. C'est ce que vous appelez un polymorphisme au moment de l'exécution. La méthode à appeler n’est pas décidée au moment de l’exécution.

Pour plus de précisions, lisez this .

88
Kazekage Gaara

Les méthodes statiques sont masquées, les méthodes non statiques sont ignorées . La différence est notable lorsque les appels ne sont pas qualifiés "quelque chose ()" ou "ceci.somain ()".

Je n'arrive pas vraiment à écrire, 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();
    }

}

SORTIE:

animal.something
dog.eat
16
WhyNotHugo

C’est la différence entre les dérogations et la dissimulation, 

  1. Si les méthodes de la classe parent et de la classe enfant sont une méthode d'instance, elle est appelée remplacement.
  2. Si les méthodes de la classe parent et de la classe enfant sont des méthodes statiques, on appelle masquage.
  3. Une méthode ne peut pas être statique dans parent et comme instance dans l'enfant. et vice versa.

enter image description here

11
Rudy

Si je comprends bien votre question, la réponse est "vous avez déjà une priorité".

"Ce qui me montre que l'écriture d'une méthode statique, avec le même nom que dans le parent, dans une sous-classe effectue à 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 nécessaire pour remplacer une méthode. Cela rend toutefois votre code plus lisible et oblige le compilateur à vérifier que vous surchargez une méthode (et que vous n'avez pas mal orthographié la méthode de la sous-classe, par exemple).

3
thagorn

Le remplacement s'effectue 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 depuis Cat (il s'agit d'une substitution). Pour le même objet acat, la méthode de classe de 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.
3
yiannis
public class First {

public void Overriding(int i) {  // will be overrided 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) {  // overrided here  }

public static void Hiding(int i) {  // hidden
                                    // because it's static } 
}

La règle de mémorisation est simple: une méthode dans la classe d'extension Ne peut pas changer statique en vide et Ne peut pas changer vide en statique. Cela entraînera une erreur de compilation.

Mais si void Name est remplacé par void Name c'est écrasant. 

Et si Nom statique est devenu Nom statique c'est masqué. (Lorsque le compilateur voit static method dans l'objet de la superclasse, il ne vérifie pas la méthode dans la sous-classe.)

2
p.karnaukhov

Dans cet extrait de code, j'utilise le 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();
}
}

Sortie:

----- 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
1
Rustem Zhunusov

Au moment de l'exécution, la version enfant d'une méthode substitué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 parente n'est jamais utilisée à moins qu'un appel explicite à la méthode parente soit référencé par .__, en utilisant la syntaxe ParentClassName.method () . Au lieu de l'exécution, la version Parent d'une méthode masquée est toujours exécutée si l'appel de la méthode est défini dans la classe.

0
Carrieukie

Comment la méthode statique se cache-t-elle en Java? La classe Cat étend la classe Animal. 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). Comment ça marche dans Heap and Stack?

0
user3924979

Dans method overriding , la résolution de la méthode est effectuée par la machine virtuelle Java sur la base d'un objet d'exécution. Tandis que dans le masquage de méthode, la résolution de la méthode est effectuée par le compilateur sur la base de références. Ainsi,

Si le code aurait été écrit en tant que,

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

La sortie serait comme ci-dessous:
Méthode par classe chez l’animal.

0
SagarS

Basé sur mes récentes études sur Java 

  • method overriding , lorsque la sous-classe a la même méthode avec la même signature dans la sous-classe.
  • Method masquant , lorsque la sous-classe a le même nom de méthode, mais un paramètre différent. Dans ce cas, vous ne remplacez pas la méthode parent, mais vous la cachez.

Exemple tiré 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 principal 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 le deuxième élément principal, nous utilisons la classe Object comme type statique. Par conséquent, lorsque nous appelons la méthode equal dans un objet Point, il attend qu'une classe Point arrive en tant que paramètre, mais que l'objet arrive. Donc, la méthode Object equals est exécutée, car nous y avons un equals (Object o). Dans ce cas, la classe du point est égale à ne remplace pas, mais masque la méthode de la classe objet égale à .

0
Karoly

La page de tutoriel Java liée explique le concept de substitution et de masquage.

Une méthode d'instance dans une sous-classe avec la même signature (nom, plus le nombre et le type de ses paramètres) et le type de retour comme 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 dans la superclasse, la méthode de la sous-classe masque celle de la superclasse.

La distinction entre le masquage d'une méthode statique et le remplacement d'une méthode d'instance a des implications importantes:

  1. La version de la méthode d'instance substituée appelée est celle de la sous-classe.
  2. La version de la méthode statique masquée appeléedépend de son invocation depuis la superclasse ou 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 se cacher pour le moment. 

Maintenant, changez 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();
0
Ravindra babu

En plus des exemples énumérés ci-dessus, voici un petit exemple de code permettant de clarifier la distinction entre masquer et remplacer:

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 de child.printParent() génère:
à cacher: Parent
à remplacer: Enfant

L’appel de child.printChild() génère:
à cacher: Enfant
à remplacer: Enfant

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

Java permet à la fois de masquer et de remplacer pour les méthodes. La même règle ne s'applique pas aux variables. Le remplacement de variables n’est pas autorisé. Par conséquent, les variables ne peuvent être que masquées (aucune différence entre les variables statiques et non statiques). L'exemple ci-dessous montre comment la méthode getName() est remplacée et la variable name est 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
Nurettin Armutcu
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
Deepak