Para las conversiones que no requieren una prueba en tiempo de ejecución, puede ser posible que el compilador de hacer algunas optimizaciones para evitar la proyección en tiempo de ejecución.
Sugiero leer el JLS Chapter 5. Conversions and Promotions para saber más sobre el tipo de conversiones que necesitan una prueba en tiempo de ejecución.
Ejemplo 5.0-1. Las conversiones en tiempo de compilación y en tiempo de ejecución
A conversion from type Object to type Thread requires a run-time check to make sure that the run-time value is actually an instance of class Thread or one of its subclasses; if it is not, an exception is thrown.
A conversion from type Thread to type Object requires no run-time action; Thread is a subclass of Object, so any reference produced by an expression of type Thread is a valid reference value of type Object.
A conversion from type int to type long requires run-time sign-extension of a 32-bit integer value to the 64-bit long representation. No information is lost.
A conversion from type double to type long requires a nontrivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.
5.1.6. Narrowing Reference Conversion:
Tales conversiones requieren una prueba en tiempo de ejecución para averiguar si el valor de referencia real es un valor legítimo de la nueva tipo. Si no, se genera una ClassCastException.
5.1.8. Unboxing Conversion; La conversión procede en tiempo de ejecución.
Véase también: 5.5.3. Checked Casts at Run-time
No es tan fácil de determinar cuando la conversión ocurrió por ejemplo:
public class Main {
private static class Child extends Parent{
public Child() {
}
}
private static class Parent {
public Parent() {
}
}
private static Child getChild() {
Parent o = new Child();
return (Child) o;
}
public static void main(final String[] args) {
Child c = getChild();
}
}
El resultado dado por javap -c Main
es:
public class Main extends java.lang.Object{
public Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method getChild:()LMain$Child;
3: astore_1
4: return
}
Si cambia el declaración de método a public static Child getChild()
el resultado es:
public class Main extends java.lang.Object{
public Main();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static Main$Child getChild();
Code:
0: new #2; //class Main$Child
3: dup
4: invokespecial #3; //Method Main$Child."<init>":()V
7: astore_0
8: aload_0
9: checkcast #2; //class Main$Child
12: areturn
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method getChild:()LMain$Child;
3: astore_1
4: return
}
Verá que el simple hecho de cambiar el acceso, puede tener un gran impacto en las posibles optimizaciones.
Buena pregunta ... pero, ¿es esto importante codificar? ¿O solo preguntas por tu propia curiosidad? – Tenner
@Tenner ¿Importa de alguna manera? –
En este ejemplo, espero que la conversión de tipos se realice durante el tiempo de compilación y no durante el tiempo de ejecución. Sin embargo, no debería necesitar enviar o a un elemento secundario para la declaración de devolución, ya que Java sabe que es de tipo Child en función del gráfico Object. – Jay