Desde ya entender el caso 1, 3 y 4, vamos a abordar el caso 2.
(Tenga en cuenta - No soy de ninguna manera un experto en el funcionamiento interno de la JVM o compiladores, pero esta es la forma en Lo entiendo. Si alguien que está leyendo esto es un experto en JVM, puede editar esta respuesta sobre cualquier discrepancia que pueda encontrar)
Un método en una subclase que tiene el mismo nombre pero una firma diferente se conoce como sobrecarga de método . La sobrecarga de métodos usa enlaces estáticos, lo que básicamente significa que el método apropiado será forzado a ser "elegido" (es decir, vinculado) en tiempo de compilación. El compilador no tiene idea sobre el tipo de tiempo de ejecución (también conocido como el tipo real) de sus objetos.Entonces cuando escribe:
// Reference Type // Actual Type
Sub sub = new Sub(); // Sub Sub
Top top = sub; // Top Sub
el compilador solo "sabe" que la parte superior es de tipo Top (también conocido como el tipo de referencia). Así que cuando se escribe más adelante:
System.out.println(top.f(str)); // Prints "subobj"
el compilador "ve" la llamada 'top.f' se refiere a un método f de la clase superior. "Sabe" que str es de tipo String que extiende Object. Entonces, desde 1) la llamada 'top.f' se refiere al método f de Top class, 2) no hay un método f en la clase Top que tome un parámetro String, y 3) porque str es una subclase de Object, el método f de Top class es la única opción válida en tiempo de compilación. Entonces, el compilador reenvía implícitamente str a su tipo principal, Object, para que pueda pasar al método f de Top. (Esto está en contraste con el enlace dinámico, donde la resolución de tipo de la línea de código anterior se aplazaría hasta el tiempo de ejecución, para ser resuelta por la JVM en lugar del compilador).
Luego, en tiempo de ejecución, en la línea de código anterior , la parte superior está bajada por la JVM a su tipo real, sub. Sin embargo, el compilador ha modificado el argumento str para que escriba Object. Entonces ahora la JVM tiene que llamar a un método f en el sub clase que toma un parámetro de tipo Objeto.
Por lo tanto, la línea de código anterior imprime "subobj" en lugar de "sub".
Para otro ejemplo muy similar, consulte: Java dynamic binding and method overriding
Actualización: Encontrado este artículo detallado sobre el funcionamiento interno de la JVM:
http://www.artima.com/underthehood/invocationP.html
os comentaba su código para que sea más clara ¿Qué está pasando:
class Top {
public String f(Object o) {return "Top";}
}
class Sub extends Top {
public String f(String s) {return "Sub";} // Overloading = No dynamic binding
public String f(Object o) {return "SubObj";} // Overriding = Dynamic binding
}
public class Test {
public static void main(String[] args) {
// Reference Type Actual Type
Sub sub = new Sub(); // Sub Sub
Top top = sub; // Top Sub
String str = "Something"; // String String
Object obj = str; // Object String
// At Compile-Time: At Run-Time:
// Dynamic Binding
System.out.println(top.f(obj)); // Top.f (Object) --> Sub.f (Object)
// Dynamic Binding
System.out.println(top.f(str)); // Top.f (Object) --> Sub.f (Object)
// Static Binding
System.out.println(sub.f(obj)); // Sub.f (Object) Sub.f (Object)
// Static Binding
System.out.println(sub.f(str)); // Sub.f (String) Sub.f (String)
}
}
Ahora tengo cómo funciona la primera línea, pero ¿cómo es que la segunda línea imprime SubObj, incluso si el en put call era top.f (str) donde str es un tipo de String? – user482594
He publicado una respuesta, ¿la miraste? Debería resolver tus dudas. Para resumir piense desde el punto de "Type Check" para el argumento pasado. Acepte la respuesta si lo encuentra útil. –