Search code examples
javacastingjava-7unboxing

Differences in auto-unboxing between Java 6 vs Java 7


I have noted a difference in auto unboxing behavior between Java SE 6 and Java SE 7. I'm wondering why that is, because I can't find any documentation of changes in this behavior between these two versions.

Here's a simple example:

Object[] objs = new Object[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

This compiles fine with javac from Java SE 7. However, if I give the compiler the "-source 1.6" argument I get an error on the last line:

inconvertible types
found   : java.lang.Object
required: int

I tried downloading the Java SE 6 to compile with the native version 6 compiler (without any -source option). It agrees and gives the same error as above.

So what gives? From some more experimentation it seems that the unboxing in Java 6 can only unbox values that clearly (at compile time) is of the boxed type. For instance, this works in both versions:

Integer[] objs = new Integer[2];
objs[0] = new Integer(5);
int myInt = (int)objs[0];

So it seems that between Java 6 and 7, the unboxing feature was enhanced so that it could cast and unbox object types in one swoop, without knowing (at compile time) that the value is of the proper boxed type. However, reading through the Java Language Specification or blog postings that were written at the time Java 7 came out, I can't see any change of this thing, so I'm wondering what the change is and what this "feature" is called?

Just a curiosity: Due the change, it is possible to trigger "wrong" unboxings:

Object[] objs = new Float[2];
objs[0] = new Float(5);
int myInt = (int)objs[0];

This compiles fine but gives a ClassCastException at runtime.

Any reference on this?


Solution

  • It looks like the language in section 5.5 Casting Conversion of Java 7 JLS was updated in comparison to the same section in the Java 5/6 JLS, probably to clarify the allowed conversions.

    Java 7 JLS says

    An expression of a reference type may undergo casting conversion to a primitive type without error, by unboxing conversion.

    Java 5/6:

    A value of a reference type can be cast to a primitive type by unboxing conversion (§5.1.8).

    The Java 7 JLS also contains a table (table 5.1) of allowed conversions (this table is not included in the Java 5/6 JLS) from reference types to primitives. This explicitly lists casts from Object to primitives as a narrowing reference conversion with unboxing.

    The reason is explained in this email:

    Bottom line: If the spec. allows (Object)(int) it must also be allowing (int)(Object).