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 Animal
classe exécute la méthode dans la Animal
classe 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!
la source
Réponses:
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 à unestatic
mé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 .
la source
private methods
? Ils ne peuvent pas l'êtreoverridden
puisque la sous-classe ne connaît pas leur existence. Par conséquent, ils pourraient l'être à lahidden
place.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:
la source
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 ().Animal()
, rappelezAnimal()
- vous est un constructeur.something()
inAnimal()
always callsomething()
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 statiqueAnimal()
est toujours appelant implicitementAnimal.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 (ieclassName.staticMethodName()
) sauf si l'appel est dans la même classe.C'est la différence entre les remplacements et le masquage,
la source
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).
la source
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:
la source
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 Name
est changé envoid Name
c'est Overriding.Et si
static Name
est changé enstatic Name
c'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.)la source
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:
la source
Basé sur mes récentes études Java
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 .
la source
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())
la source
La page de didacticiel Java liée explique le concept de remplacement et de masquage
La distinction entre masquer une méthode statique et remplacer une méthode d'instance a des implications importantes:
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();
la source
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 variablename
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; } }
la source
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.
la source
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.
la source
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.
la source
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.
la source
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?
la source