Héritage Java: méthodes écrasées ou cachées
Lorsqu'une classe étend une autre, elle hérite de toutes les méthodes et variables de la superclasse. Les deux méthodes et les variables peuvent être utilisées différemment dans la sous-classe, si vous définir différemment dans la sous-classe avec la même signature. Oracle distingue entre l'écriture et la dissimulation (http://docs.oracle.com/javase/tutorial/java/IandI/override.html). Il dit qu'une méthode d'instance écrase la méthode de sa superclass, alors qu'une méthode de classe la cache. "La distinction entre se cacher et le dépassement a des implications importantes. La version de la méthode overridden qui est invoquée est celle de la sous-classe. La version de la méthode cachée qui est invoquée dépend de si elle est invoquée à partir de la superclasse ou de la sous-classe."
laisse supposer que j'ai 2 classes Oui et peut-être. Oui s'étend peut-être. Il a peut-être une ficelle A.
class Maybe {
String a;
public static void printOut() {
System.out.println("Maybe");
}
public void printAndSet() {
a = "Maybe";
System.out.println(a);
}
}
class Yes extends Maybe {
public static void printOut() {
System.out.println("Yes");
}
pubilc void printAndSet() {
a = "Yes";
}
}
class Print{
public static void mail(String[] args) {
Maybe m = new Maybe();
Yes y = new Yes();
Maybe.printOut();
Yes.printOut();
m.printAndSet();
y.printAndSet();
}
et je dis: il va imprimer peut-être oui peut-être Oui
mais après que j'ai lu le Oracle article, j'ai pensé qu'il aurait à imprimer:
yes
yes
maybe
yes
parce que la méthode instance écrase sa méthode superclass.
je suis tout à fait sûr que j'ai raison avec la sortie, mais je suis sûr aswell, que L'Oracle sait mieux, je pense que je n'ai pas compris l'article. Il ne peut pas être vrai que lorsque j'appelle une méthode d'instance à partir d'un objet d'une superclasse, elle utilise la méthode écrasée. Donc je ne comprends pas pourquoi distinguer de les écraser et de les cacher! Quelqu'un peut-il vous aider?
éditer; Code inséré au lieu de décrire les classes!
3 réponses
les méthodes statiques ne peuvent pas être dépassées du tout. Ils ne s'appellent pas polymorphiquement, car ils n'agissent pas sur une instance de la classe, mais sur la classe elle-même.
si vous appelez Maybe.printOut()
, il appellera la méthode statique printOut()
définie dans Maybe
. Le fait qu'il existe également une méthode printOut()
définie dans Yes
n'est pas pertinent: ces deux méthodes n'ont rien en commun, sauf leur nom.
Notez que vous pouvez confirmer ou infirme vos doutes en écrivant un programme et l'exécuter.
le problème avec les méthodes de dissimulation ne se produit que lorsque vous commencez à appeler des méthodes statiques sur une instance d'un objet. C'est une très mauvaise pratique, et ne devrait jamais être fait. Si vous ne respectez pas cette règle, et avoir le suivant:
Maybe m = new Maybe();
Maybe y = new Yes();
m.printOut(); // DON'T DO THAT: it should be Maybe.printOut();
y.printOut(); // DON'T DO THAT: it should be Maybe.printOut() or Yes.printOut();
le résultat sera maybe maybe
, parce que dans le cas de méthodes statiques, ce qui compte est pas le type de béton des objets ( Maybe
et Yes
), mais leur , a déclaré ( Maybe
et Maybe
).
public class Parent {
public String test(){
return "p";
}
public static String testStatic(){
return "sp";
}
}
public class Child extends Parent {
public String test(){
return "c";
}
public static String testStatic(){
return "sc";
}
}
public class Demo{
public static void main(String[] args) {
Parent p =new Parent();
Child c = new Child();
Parent pc = new Child();
System.out.println(p.test());
System.out.println(c.test());
System.out.println(pc.test());
//Although this is not the correct way of calling static methods
System.out.println(p.testStatic());
System.out.println(c.testStatic());
System.out.println(pc.testStatic());
}
}
sortie sera: - (méthode statique vs méthode d'instance)
p C C sp sc sp
Prenez l'exemple suivant, basé sur votre exemple:
public class SO11720216 {
static class Maybe {
public static void hidden() { System.out.println("static maybe"); }
public void overwritten() { System.out.println("instance maybe"); }
public void inherited() { hidden(); }
public void called() { overwritten(); inherited(); }
}
static class Yes extends Maybe {
public static void hidden() { System.out.println("static yes"); }
public void overwritten() { System.out.println("instance yes"); }
}
public static void main(String[] args) {
Maybe m = new Maybe();
Yes y = new Yes();
m.called(); /* prints:
instance maybe
static maybe
*/
y.called(); /* prints:
instance yes
static maybe
*/
Yes.hidden(); /* prints: static yes */
y.hidden(); /* bad style! prints: static yes */
}
}
l'appel à overwritten
sera remplacé par chaque classe dérivée. Ainsi chaque méthode utilisera l'implémentation appartenant à l'objet courant. D'un autre côté, l'appel à hidden
utilisera toujours l'implémentation de la classe de définition. Par conséquent Maybe.called
appellera toujours Maybe.hidden
, et jamais Yes.hidden
. Pour appeler Yes.hidden
, vous devrez le faire de l'intérieur d'un méthode dans Yes
, ou en utilisant un nom qualifié.
pour dire autrement:
- à remplacer une méthode signifie que chaque fois que la méthode est appelée sur un objet de la classe dérivée , la nouvelle implémentation sera appelée.
- à hide une méthode signifie qu'un appel sans réserve à ce nom (comme l'appel
hidden()
dans leinherited()
méthode de mon exemple ci-dessus) dans le champ d'application de cette classe (c.-à-d. dans le corps de l'une de ses méthodes, ou lorsque qualifié avec le nom de cette classe) va maintenant appeler une fonction complètement différente, exigeant une qualification pour accéder à la méthode statique du même nom de la classe mère.
peut-être que votre confusion vient du fait que vous avez supposé overwriting affecter tous les appels à la méthode, même pour les objets de la classe de base.