2012-10-08 70 views
8

下面的程序分别打印“假”与“真”:不需要自动装箱魔术

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

所以不会是一个长期的,但一个双。然而,它的工作如预期正常类: 有

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

会打印出“真”:

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

这意味着它不工作一样像上面的例子。

我确定有一些与自动装箱有关的东西,但它真的是它的工作方式?为什么她使用装箱,当Number类是Long和Double的超类,以便可以将表达式评估为Number?

这真的很痛苦,因为当打印n时,它会打印为双值。 (我知道这是很容易的解决方法,但让我抓狂)

+0

的':'取型最后一个表达式。如果你使它成为'null',那将是'Long':P。 –

+0

不,它不需要最后一个表达式的类型,只需看第二个例子即可。当然,代码仅仅是一个例子,但想象一下,真实的布尔信息在现在的'真实'站在了最前面。 – poroszd

+2

为何选择近距离投票?这对我来说看起来像个很好的问题。 –

回答

2

它只是 放眼字节代码,你会看到(简单地修改你的例子)

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)); 

字节码

_new '爪哇/郎/龙'

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 

主要点是l2d它使下一步

从堆栈中弹出一个长整数,将其转换为双精度浮点数,并将双精度值推回堆栈。 请注意,这可能会导致精度损失(双精度型中的有效位数为54位,与长度为64位相比),尽管不会造成损失 (因为双精度的范围大于范围 长)。舍入是使用IEEE 754轮到模式完成的。

毕竟这是很好的,所以你必须实例,但与long值!如果你在调试模式下看看,你会看到我们的数字是双但从长期价值,它上面描述中,字节码

我们可以看到它在字节码

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

甜,很高兴知道(即使这回答如何,而不是为什么) 。 – poroszd