Faulty behavior in Java in conditional expression
A simple expression:
Object val = true ? 1l : 0.5;
What type is val? Well, logically, val should be a Long object with value 1. But Java thinks that val is a Double with value 1.0.
It doesn't have to to anything with autoboxing as
Object val = true ? new Long(1) : new Double(0.5);
results with same behavior.
Just to clarify:
Object val = true ? "1" : 0.5;
r开发者_C百科esults in the correct String.
Can anybody explain me why they have defined this like that? For me it seems to be rather really bad designed or actually a bug.
This is described in the Java Language Specification Section 15.25 (relevant parts in bold face):
The type of a conditional expression is determined as follows:
If the second and third operands have the same type [...]
If one of the second and third operands is of type boolean [...]
If one of the second and third operands is of the null type [...]
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
If one of the operands is of type byte [...]
If one of the operands is of type T where T is byte, short, or char, [...]
If one of the operands is of type Byte [...]
If one of the operands is of type Short [...]
If one of the operands is of type; Character [...]
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).
Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).
The "lub" mentioned in the last paragraph stands for least upper bound and refers to the most specific super type common for T1 and T2.
As for the case with Object val = true ? 1l : 0.5;
I agree that it would be more precise if it applied rule 5 (on the boxed values). I guess the rules would become ambiguous (or even more complicated) when taking autoboxing into account. What type would for instance the expression b ? new Byte(0) : 0.5
have?
You can however force it to use rule 5 by doing
Object val = false ? (Number) 1L : .5;
Because the expression needs to be of a type.
If you do 1l + 0.5d, you end with 1.5d because the compiler changes automatically the types to the one which can allow all possible results.
In your case, the compiler sees ? and assigns the result of the expression the double using the same rule (you can write a long as a double, but not all doubles as longs).
That's not a design flaw:
The compiler has to determine the type of the entire expression true ? 1l : 0.5
. It tries using a type where as few conversions as possible are required.
As 0.5 does not fit into a long
(without loss of precision), the result of the expression can't be long - therefore, it has to be double
and the long is simply converted (no loss of precision).
Note that you can't have an expression conditionally having different types - a tertiary expression has to evaulate to the same type regardless of the condition.
In the second snippet, Object is the only compatible type - the Double gets boxed and the String can be simply assigned.
When you write
Object val = true ? new Long(1) : new Double(0.5);
you need to consider that
(new Long(1) : new Double(0.5))
needs to have a value... The compiler needs to come up with a type that covers both possible values. For your example, it was double.
I cannot provide you with a good reason, but the type of the expression is given by the Java Language Specification: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25
In the JLS all the numeric types are treated as special cases.
精彩评论