statement - the ?:operator in java
Tipo de retorno "incorrecto" cuando se usa if vs. ternary opertator en Java (2)
Además de la respuesta de @Jon, mirando el código de bytes que ve:
public static java.lang.Object getWithQuestionMark();
Code:
0: getstatic #7; //Field doubleValue:Ljava/lang/Double;
3: ifnonnull 16
6: getstatic #8; //Field longValue:Ljava/lang/Long;
9: invokevirtual #9; //Method java/lang/Long.longValue:()J
12: l2d
13: goto 22
16: getstatic #7; //Field doubleValue:Ljava/lang/Double;
19: invokevirtual #10; //Method java/lang/Double.doubleValue:()D
22: invokestatic #11; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
25: astore_0
26: aload_0
27: areturn
Mientras que si le dices al compilador que no estás interesado en los números:
public static Object getWithQuestionMark() {
return doubleValue == null ? (Object)longValue : (Object)doubleValue;
}
obtendrás lo que estabas buscando (bytecode)
public static java.lang.Object getWithQuestionMark();
Code:
0: getstatic #7; //Field doubleValue:Ljava/lang/Double;
3: ifnonnull 12
6: getstatic #8; //Field longValue:Ljava/lang/Long;
9: goto 15
12: getstatic #7; //Field doubleValue:Ljava/lang/Double;
15: areturn
salidas:
$ java IfTest
class java.lang.Long
class java.lang.Long
En la siguiente clase, el tipo de retorno de los dos métodos es inconsistente con la idea de que el operador ternario:
return condition?a:b;
es equivalente a
if(condition) {
return a;
} else{
return b;
}
El primero devuelve un Doble y el segundo un Largo:
public class IfTest {
public static Long longValue = 1l;
public static Double doubleValue = null;
public static void main(String[] args) {
System.out.println(getWithIf().getClass());// outpus Long
System.out.println(getWithQuestionMark().getClass());// outputs Double
}
public static Object getWithQuestionMark() {
return doubleValue == null ? longValue : doubleValue;
}
public static Object getWithIf() {
if (doubleValue == null) {
return longValue;
} else {
return doubleValue;
}
}
}
Me imagino que esto tiene que ver con el compilador de conversión angosta del tipo de retorno de getWithQuestionMark()
pero, ¿es correcto el lenguaje? Ciertamente no es lo que hubiera esperado.
Cualquier información más bienvenida!
Edición: hay muy buenas respuestas a continuación. Además, la siguiente pregunta a la que hace referencia @sakthisundar explora otro efecto secundario de la promoción de tipo que se produce en el operador ternario: operador ternario complicado en Java - autoboxing
Básicamente sigue las reglas de la sección 15.25 de JLS , específicamente:
De lo contrario, si los operandos segundo y tercero tienen tipos que son convertibles (§5.1.8) a tipos numéricos, entonces hay varios casos:
[...]
De lo contrario, la promoción numérica binaria (§5.6.2) se aplica a los tipos de operandos, y el tipo de expresión condicional es el tipo promovido de los operandos segundo y tercero.
Por lo tanto , se sigue la sección 5.6.2 , que básicamente implica desempaquetar, por lo que hace que su expresión funcione como si longValue
y doubleValue
fueran de tipo long
y double
respectivamente, y la promoción de ampliación se aplica al long
para obtener un tipo de resultado general de double
.
Ese double
se encuadra para devolver un Object
del método.