最近,我遇到了Java的陷阱,代码在这里:
Number value = new Integer(10);
value = value instanceof Long ? new Long(-value.longValue()) : new Integer(-value.intValue());
System.out.println(value instanceof Integer);
System.out.println(value.getClass());
我认为输出是:
真
class java.lang.Integer
但是,我错了,正确的输出恰恰相反:
假
class java.lang.Long
我无法理解为什么。所以我使用javap -c
反汇编类文件,以下两行(说明)对我来说很奇怪:
50: i2l
51: invokestatic #10 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
为什么呢?我想要与对象value
相同的实例,为什么它给了我不同的?
非常感谢您的帮助。
答案 0 :(得分:2)
三元运算符?接收两个操作数,即 new Long(-value.longValue())和 new Integer(-value.intValue() )。
根据Java语言规范http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.2,两个操作数首先将被取消装箱(Long-> long)和(Integer-> int),请参阅http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.8,然后以下规则是施加:
如果任一操作数的类型为double,则另一个操作数转换为double。 否则,如果任一操作数的类型为float,则另一个操作数转换为float。 否则,如果任一操作数的类型为long,则另一个操作数转换为long。 否则,两个操作数都将转换为int。
由于在取消装箱步骤之后,其中一个操作数的类型为 long ,另一个操作数将转换为long。这应该可以解释你的结果。
答案 1 :(得分:1)
编译器需要格式化条件语句以返回单个类型且不超过一个:
value = value instanceof Long ? new Long(-value.longValue()) : new Integer(-value.intValue());
三元运算符需要决定转换两种可能的返回类型之一,以使返回类型保持一致。
我发现最简单的方法就像编写方法一样:
public Long getNumber(int n) {
if (value instanceof Long) {
return new Long(-value.longValue());
} else {
return new Integer(-value.intValue()); // Not consistent with return type
}
}
您需要在此实例中指定一致的返回类型。如果您将它们全部作为Number
返回,那么它应该可以正常运行:
public Number getNumber(int n) {
if (value instanceof Long) {
return (Number) new Long(-value.longValue());
} else {
return (Number) new Integer(-value.intValue());
}
}
同样地:
value = value instanceof Long ? (Number) new Long(-value.longValue()) : (Number) new Integer(-value.intValue());
为您提供所需的输出。
Java三元运算符如何决定这些转换的规则概述为here in the Java Docs
它们基于信息保存的逻辑:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
只是给出一些关于这些规则背后的逻辑的背景,以便它们看起来不那么武断。
Double
具有先例,因为它是最具体的,即您可以想象将double
切成int
会丢失信息((int) 0.555 -> 0
)而不是转换int
到double
不会丢失任何信息((double) 1 -> 1.0
)
然后Float
,因为float
的精确度低于double
但超过long
或int
。
long
,因为它是更精确的版本int
,最后它们被视为int
s
因为int
是最不具体的,所以通常会转换为其他Number
格式。