annotation - polymorphism java
Anulando vs Ocultando Java-Confundido (12)
¿Cómo se está escondiendo el método estático en java? La clase de gato está extendiendo la clase Animal. Entonces, en la clase Cat tendremos ambos métodos estáticos (me refiero al método estático de la clase Child y el método estático de la clase Parent). Pero, ¿cómo JVM oculta el método estático Parent? ¿Cómo se trata en Heap and Stack?
Estoy confundido sobre cómo Overriding difiere de Hiding en Java. ¿Alguien puede proporcionar más detalles sobre cómo difieren? Leí el tutorial de Java, pero el código de muestra aún me dejó confundido.
Para ser más claro, entiendo que Anular bien. Mi problema es que no veo que esconderse sea diferente, excepto por el hecho de que uno está en el nivel de instancia mientras que el otro está en el nivel de clase.
Mirando el código tutorial de 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.");
}
}
Entonces tenemos un gato de subclase:
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();
}
}
Luego dicen:
El resultado de este programa es el siguiente:
Método de clase en Animal.
El método de instancia en Cat.
Para mí, el hecho de llamar a un método de clase testClassMethod () directamente desde la clase Animal, ejecuta el método en la clase Animal es bastante obvio, nada especial allí. Luego llaman a testInstanceMethod () desde una referencia a myCat, así que de nuevo es bastante obvio que el método ejecutado entonces es el de la instancia de Cat.
Por lo que veo, el ocultamiento de las llamadas se comporta como una anulación, entonces ¿por qué hacer esa distinción? Si ejecuto este código usando las clases anteriores:
Cat.testClassMethod();
Obtendré: el método de clase en Cat. Pero si elimino el método testClassMethod () de Cat, obtendré: El método de clase en Animal.
Lo cual me muestra que al escribir un método estático, con la misma firma que en el elemento primario, en una subclase prácticamente se anula.
Afortunadamente, estoy dejando claro dónde estoy confundido y alguien puede arrojar algo de luz. Muchas gracias de antemano!
Además de los ejemplos enumerados anteriormente, aquí hay un pequeño código de muestra para aclarar la distinción entre ocultar y anular:
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();
}
}
La llamada de los child.printParent()
de child.printParent()
:
estar oculto: padre
ser anulado: Niño
La llamada de los child.printChild()
de child.printChild()
:
estar oculto: niño
ser anulado: Niño
Como podemos ver a partir de las salidas anteriores (especialmente las salidas marcadas en negrita), el ocultamiento de métodos se comporta de manera diferente a la anulación.
Java permite ocultar y anular solo los métodos. La misma regla no se aplica a las variables. La anulación de variables no está permitida, por lo que las variables solo se pueden ocultar (no hay diferencia entre variable estática o no estática). El siguiente ejemplo muestra cómo se anula el método getName()
y se oculta el name
la variable:
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;
}
}
Basado en mis estudios recientes de Java
- método que reemplaza , cuando la subclase tiene el mismo método con la misma firma en la subclase.
- Método de ocultación , cuando la subclase tiene el mismo nombre de método, pero diferentes parámetros. En este caso, no anula el método principal, sino que lo oculta.
Ejemplo del libro OCP Java 7, página 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
}
}
pero si escribimos el siguiente mensaje principal:
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
}
En la segunda, usamos la clase Object como tipo estático, por lo que cuando llamamos al método igual en el objeto Point, está esperando que una clase Point llegue como parámetro, pero viene Object. Entonces la clase Object es igual al método que se ejecuta, porque tenemos un igual (Objeto o) allí. En este caso, la clase Point es igual a dosen''t overrides, pero oculta el método Object class equals .
En este fragmento de código utilizo el modificador de acceso ''privado'' en lugar de ''estático'' para mostrarle la diferencia entre los métodos de ocultación y los métodos de anulación.
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();
}
}
Salida:
----- 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
Esta es la diferencia entre anulaciones y ocultación,
- Si ambos métodos en la clase principal y la clase secundaria son un método de instancia, llamó a las anulaciones.
- Si ambos métodos en la clase principal y la clase secundaria son métodos estáticos, se llama oculto.
- Un método no puede ser estático en el padre y como una instancia en el niño. y viceversa.
La anulación ocurre solo con métodos de instancia. Cuando el tipo de la variable de referencia es Animal y el objeto es Cat, el método de instancia se llama desde Cat (esto está anulando). Para el mismo objeto de acat, se usa el método de clase de Animal.
public static void main(String[] args) {
Animal acat = new Cat();
acat.testInstanceMethod();
acat.testClassMethod();
}
La salida es:
The instance method in Cat.
Class method in Animal.
La página del tutorial java enlazado explica el concepto de anulación y ocultación
Un método de instancia en una subclase con la misma firma (nombre, más el número y el tipo de sus parámetros) y el tipo de devolución como un método de instancia en la superclase anula el método de la superclase.
Si una subclase define un método estático con la misma firma que un método estático en la superclase, entonces el método en la subclase oculta el de la superclase.
La distinción entre ocultar un método estático y anular un método de instancia tiene implicaciones importantes:
- La versión del método de instancia anulada que se invoca es la de la subclase.
- La versión del método estático oculto que se invoca depende de si se invoca desde la superclase o la subclase.
Volviendo a su ejemplo:
Animal myAnimal = myCat;
/* invokes static method on Animal, expected. */
Animal.testClassMethod();
/* invokes child class instance method (non-static - it''s overriding) */
myAnimal.testInstanceMethod();
La declaración anterior no muestra ocultarse todavía.
Ahora cambie el código de la siguiente manera para obtener diferentes resultados:
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();
Los métodos estáticos están ocultos, los métodos no estáticos son anulados. La diferencia es notable cuando las llamadas no están calificadas como "algo ()" vs "this.something ()".
Realmente no puedo ponerlo en palabras, así que aquí va un ejemplo:
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();
}
}
SALIDA:
animal.something
dog.eat
Over-riding básicamente es compatible con el encuadernado tardío. Por lo tanto, qué método se llamará se decide en tiempo de ejecución. Es para métodos no estáticos. Ocultar es para todos los demás miembros (métodos estáticos, miembros de instancia, miembros estáticos). Se basa en la vinculación temprana. Más claramente, el método o miembro a ser llamado o utilizado se decide durante el tiempo de compilación.
En su ejemplo, la primera llamada, Animal.testClassMethod()
es una llamada a un método static
, por lo tanto, es bastante seguro en cuanto a qué método se va a llamar.
En la segunda llamada, myAnimal.testInstanceMethod()
, llama a un método no estático. Es lo que llamas polimorfismo en tiempo de ejecución. No se decide hasta el tiempo de ejecución qué método debe invocarse.
Para mayor aclaración, lea this .
Si entiendo tu pregunta correctamente, entonces la respuesta es "ya estás superando".
"Lo que me muestra que escribir un método estático, con el mismo nombre que en el elemento primario, en una subclase prácticamente invalida".
Si escribe un método en una subclase con exactamente el mismo nombre que un método en una superclase, anulará el método de la superclase. La anotación @Override no es necesaria para anular un método. Sin embargo, hace que su código sea más legible y obliga al compilador a verificar que en realidad está anulando un método (y no ha escrito mal el método de la subclase, por ejemplo).
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 regla para memorizar es simple: un método para extender la clase no puede cambiar estático a vacío y no puede cambiar de vacío a estático. Causará el error de compilación.
Pero si el Nombre nulo ha cambiado a Nombre nulo , está Anulando.
Y si el Nombre estático cambió a Nombre estático , está Oculto. (Cuando el compilador ve el método estático en el objeto de la superclase, entonces no verifica el método en la subclase).
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())