2012-10-08 63 views
8

Los siguientes programas grabados, respectivamente, 'falso' y 'verdadero':no deseado magia autoboxing en Números

Number n = true ? new Long(1) : new Double(2.0); 
System.out.println(n instanceof Long); 
System.out.println(n instanceof Double); 

lo tanto, no pasará mucho más que un doble. Sin embargo, funciona según lo previsto en las clases normales: Tener

class B {} 
class D1 extends B {} 
class D2 extends B {} 

esto imprimirá 'verdadero':

B b = true ? new D1() : new D2(); 
System.out.println(b instanceof D1); 

lo que significa que no está funcionando de la misma como el ejemplo anterior.

Estoy seguro de que hay algo relacionado con el autoboxing, pero ¿realmente es así como debería funcionar? ¿Por qué usa el boxeo cuando la clase numérica es una superclase tanto de largo como de doble, por lo que esa expresión podría evaluarse en Número?

Es realmente un dolor, porque al imprimir el n, se imprime como un valor doble. (Sé que es fácil de solucionar este problema, pero me volvió loca)

+0

El ':?' Toma el tipo de de la última expresión Si lo hiciste 'nulo' sería un' Largo': P. –

+0

No, no toma el tipo de la última expresión, solo mira el segundo ejemplo. Por supuesto, el código es solo un ejemplo, pero imagina que hay algo de información booleana real donde ahora lo 'verdadero' se encuentra en el tren. – poroszd

+2

¿Por qué los votos cercanos? Esto parece una muy buena pregunta para mí. –

Respuesta

7

Echemos un vistazo al libro del abogado de la lengua aquí: JLS §15.25

El tipo de una expresión condicional se determina de la siguiente manera:

  • Si el segundo y tercer operandos tienen el mismo tipo (que puede ser el tipo nulo), ese es el tipo de expresión condicional.

Long y Double no son del mismo tipo - no se aplican.

  • Si uno de los segundo y tercer operandos es de tipo T primitivo, y el tipo de la otra es el resultado de aplicar la conversión de boxeo (§5.1.7) a T, entonces el tipo de la expresión condicional es T.

Ni valor es primitiva - no se aplica.

  • Si uno de los segundo y tercer operandos es del tipo nulo y el tipo de la otra es un tipo de referencia, entonces el tipo de la expresión condicional es que tipo de referencia.

Ninguno de los dos valores es nulo: no corresponde.

  • De lo contrario, si el segundo y tercer operandos tienen tipos que sean convertibles (§5.1.8) a tipos numéricos, entonces hay varios casos:
    • [... casos especiales para los bytes/corto/char y sus equivalentes en caja ...]
    • De lo contrario, la promoción numérica binaria (§ 5.6.2) se aplica a los tipos de operando, y el tipo de expresión condicional es el tipo promovido del segundo y tercer operandos.

esta regla no se aplican aquí, lo que significa que el tipo de resultado del operador condicional es como si ambos valores fueron sin embalaje. Se supone que el razonamiento detrás de eso fue que de lo contrario Number n = bool ? 1 : 2.0 y Number n = bool ? new Long(1) : new Double(2.0) tienen valores diferentes. Este comportamiento también sería inesperado y, lo que es peor, inconsistente.

2

Su simplemente observe el código de bytes y verá (simplemente modificado su ejemplo)

Number n = true ? new Long(166666) : new Double(24444.0); 
System.out.println(Boolean.toString(n instanceof Long)); 
System.out.println(Boolean.toString(n instanceof Double)); 

código de bytes

_new 'java/lang/Long'

dup 
ldc 166666 
invokespecial 'java/lang/Long.<init>','(J)V' 
invokevirtual 'java/lang/Long.longValue','()J' 
l2d 
invokestatic 'java/lang/Double.valueOf','(D)Ljava/lang/Double;' 
astore 1 

El punto principal es l2d hace los próximos pasos

Aparece un entero largo fuera de la pila, lo arroja en un número de coma flotante de doble precisión , y empuja la doble hacia la pila. Observe que esto puede causar pérdida de precisión (el significado en un doble es 54 bits, en comparación con 64 bits para el largo) aunque no la pérdida de magnitud (ya que el rango de un doble es mayor que el rango de ) El redondeo se realiza utilizando el modo IEEE 754 redondeado a más cercano.

Y después de todo esto es bueno, por lo que tendrá doble ejemplo pero con largo Valor! Si nos fijamos en modo de depuración, verá que nuestro número es el doble, pero el valor de largo, él se describe anteriormente en el código de bytes

lo podemos ver en el código de bytes

getstatic 'java/lang/System.out','Ljava/io/PrintStream;' 
aload 1 
_instanceof 'java/lang/Long' 
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;' 
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V' 
getstatic 'java/lang/System.out','Ljava/io/PrintStream;' 
aload 1 
_instanceof 'java/lang/Double' 
invokestatic 'java/lang/Boolean.toString','(Z)Ljava/lang/String;' 
invokevirtual 'java/io/PrintStream.println','(Ljava/lang/String;)V' 
return 
+0

Dulce, es bueno saber (incluso si esto responde al cómo, no el por qué) . – poroszd