identifique - ¿Qué es el método oculto en Java? Incluso la explicación de JavaDoc es confusa
javadoc pdf (5)
Javadoc dice:
la versión del método oculto que se invoca es la de la superclase, y la versión del método reemplazado que se invoca es la de la subclase.
no me suena una campana. Cualquier ejemplo claro que demuestre el significado de esto será muy apreciado.
En primer lugar, ¿qué se entiende por método de ocultación?
Método de ocultamiento significa que la subclase ha definido un método de clase con la misma firma que un método de clase en la superclase. En ese caso, el método de la superclase está oculto por la subclase. Significa que: La versión de un método que se ejecuta NO será determinada por el objeto que se utiliza para invocarlo . De hecho, estará determinado por el tipo de variable de referencia utilizada para invocar el método .
¿Qué se entiende por anulación de método?
La anulación de método significa que la subclase ha definido un método de instancia con la misma firma y el mismo tipo de retorno (incluido el tipo covariante) que el método de instancia en la superclase. En ese caso, la subclase anula (reemplaza) el método de superclase. Significa que: La versión del método que se ejecuta estará determinada por el objeto que se utiliza para invocarlo . No estará determinado por el tipo de variable de referencia utilizada para invocar el método .
¿Por qué no se pueden anular los métodos estáticos?
Porque los métodos estáticos se resuelven estáticamente (es decir, en tiempo de compilación) en función de la clase a la que se invocan y no dinámicamente como en el caso de los métodos de instancia que se resuelven polimórficamente en función del tipo de tiempo de ejecución del objeto.
¿Cómo deben accederse los métodos estáticos?
Se debe acceder a los métodos estáticos de forma estática. es decir, por el nombre de la clase en sí misma en lugar de usar una instancia.
Aquí está la demostración corta para el método de anulación y ocultación:
class Super
{
public static void foo(){System.out.println("I am foo in Super");}
public void bar(){System.out.println("I am bar in Super");}
}
class Child extends Super
{
public static void foo(){System.out.println("I am foo in Child");}//Hiding
public void bar(){System.out.println("I am bar in Child");}//Overriding
public static void main(String[] args)
{
Super sup = new Child();//Child object is reference by the variable of type Super
Child child = new Child();//Child object is referenced by the variable of type Child
sup.foo();//It will call the method of Super.
child.foo();//It will call the method of Child.
sup.bar();//It will call the method of Child.
child.bar();//It will call the method of Child again.
}
}
La salida es
I am foo in Super
I am foo in Child
I am bar in Child
I am bar in Child
Claramente, como se especifica, dado que foo
es el método de clase, entonces la versión de foo
invocada estará determinada por el tipo de variable de referencia (es decir, Super o Child) que hace referencia al objeto de Child
. Si se hace referencia a foo
se llama a foo
de Super
. Y si se hace referencia a Child
variable Child
entonces se llama a foo
of Child
.
Considerando que ,
Dado que bar
es el método de instancia, la versión de la bar
invocada está determinada únicamente por el objeto (es decir, Child
) que se utiliza para invocarlo. No importa a través de qué variable de referencia ( Super
o Child
) se llame, el método que se va a llamar es siempre de Child
.
Por ejemplo, puede anular los métodos de instancia en una superclase pero no estática.
Ocultar es clase primaria tiene un método estático llamado Foo y la clase secundaria también tiene un método estático llamado Foo.
Otro escenario es que el padre tiene un método estático llamado Cat y la subclase tiene un método de instancia llamado Cat. (estática e instancia con la misma firma no se pueden mezclar).
public class Animal {
public static String getCat() { return "Cat"; }
public boolean isAnimal() { return true; }
}
public class Dog extends Animal {
// Method hiding
public static String getCat() { }
// Not method hiding
@Override
public boolean isAnimal() { return false; }
}
Si una subclase define un método de clase con la misma firma que un método de clase en la superclase, el método en la subclase oculta el de la superclase.
Los métodos ocultos están en contexto estático, creo. Los métodos estáticos no se anulan, per se, porque la resolución de las llamadas a métodos las realiza el compilador en el momento de la compilación. Entonces, si defines un método estático en la clase base con la misma firma que el presente en la clase padre, entonces el método en la subclase oculta el método heredado de la superclase.
class Foo {
public static void method() {
System.out.println("in Foo");
}
}
class Bar extends Foo {
public static void method() {
System.out.println("in Bar");
}
}
Sobrescribir un método significa que siempre que se llame al método sobre un objeto de la clase derivada, se llamará a la nueva implementación.
Ocultar un método significa que una llamada no calificada a ese nombre en el ámbito de esta clase (es decir, en el cuerpo de cualquiera de sus métodos, o cuando esté calificado con el nombre de esta clase) ahora llamará a una función completamente diferente, que requiere una calificación para acceder al método estático del mismo nombre de la clase padre .
Más descripción Herencia de Java: métodos sobrescritos u ocultos
public class Animal {
public static void foo() {
System.out.println("Animal");
}
}
public class Cat extends Animal {
public static void foo() { // hides Animal.foo()
System.out.println("Cat");
}
}
Aquí, se dice que Animal.foo()
oculta Animal.foo()
. Ocultar no funciona como anulación, porque los métodos estáticos no son polimórficos. Entonces, sucederá lo siguiente:
Animal.foo(); // prints Animal
Cat.foo(); // prints Cat
Animal a = new Animal();
Animal b = new Cat();
Cat c = new Cat();
Animal d = null;
a.foo(); // should not be done. Prints Animal because the declared type of a is Animal
b.foo(); // should not be done. Prints Animal because the declared type of b is Animal
c.foo(); // should not be done. Prints Cat because the declared type of c is Cat
d.foo(); // should not be done. Prints Animal because the declared type of d is Animal
Llamar a métodos estáticos en instancias en lugar de clases es una práctica muy mala, y nunca debería hacerse.
Compare esto con los métodos de instancia, que son polimórficos y se anulan. El método llamado depende del tipo de tiempo de ejecución concreto del objeto:
public class Animal {
public void foo() {
System.out.println("Animal");
}
}
public class Cat extends Animal {
public void foo() { // overrides Animal.foo()
System.out.println("Cat");
}
}
Entonces sucederá lo siguiente:
Animal a = new Animal();
Animal b = new Cat();
Animal c = new Cat();
Animal d = null;
a.foo(); // prints Animal
b.foo(); // prints Cat
c.foo(); // prints Cat
d.foo(): // throws NullPointerException