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?
The difference between Java 6 and Java 7 are in terms of the new features introduced in Java 7. Java 7 saw the upgrading of class loader architecture due to which the underlying resources can get free and the memory gets free as well.
The automatic conversion of primitive data types into its equivalent Wrapper type is known as boxing and opposite operation is known as unboxing. This is the new feature of Java5.
The most obvious reasons for moving from Java 6 to Java 8 are new language features and security improvements. Aside to this, Java 8 is a bigger milestone in the Java programming language history and brings Java development to a completely new level.
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called unboxing.
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).
You are right; to put it more simply:
Object o = new Integer(1234); int x = (int) o;
This works in Java 7, but gives a compilation error in Java 6 and below. Strangely, this feature is not prominently documented; for example, it's not mentioned here. It's debatable if it's a new feature or a bug fix (or a new bug?), see some related info and discussion. The consensus seems to point to an ambiguity in the original spec, which led to a slightly incorrect/inconsistent implementation on Java 5/6, which was fixed in 7, because it was critical for implementation of JSR 292 (Dynamically Typed Languages).
Java autoboxing has now some more traps and surprises. For example
Object obj = new Integer(1234); long x = (long)obj;
will compile, but fail (with ClassCastException
) at runtime. This, instead, will work:
long x = (long)(int)obj;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With