Is this a bug or feature? The following code runs fine in Java 7 but throws an exception in Java 8:
The last command throws a ClassCast exception in Java8, all the "equivalent" commands above work the same way.
The problem, I think, is that in Java 8, the compiler decides to use String.value(char[])
on the last line instead of String.value(Object)
as in Java 7. I would think this should behave the same way for backward compatibility. Am I missing something?
Note: As Marko suggested this is probably related to target type inference introduced in Java 8.
public class Test { public static void main(String[] args) { System.out.println( getVal().getClass()); // String System.out.println( String.valueOf(Test.<Object>getVal()) ); // "abc" Object obj = getVal(); System.out.println( String.valueOf(obj) ); // "abc" System.out.println( String.valueOf(getVal()) ); // 7: "abc", 8: Exception } // returns a string for simplicity; imagine that given a field, it fetches values from a database @SuppressWarnings("unchecked") public static <T> T getVal() { return (T) "abc"; } }
Result in Java 7:
class java.lang.String abc abc abc
Result in Java 8:
class java.lang.String abc abc Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to [C at Test.main(Test.java:11)
(Note: [C is an array of chars)
Both Java's are on windows:
java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) Client VM (build 24.45-b08, mixed mode, sharing) java version "1.8.0_05" Java(TM) SE Runtime Environment (build 1.8.0_05-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
Key differences between Java 7 vs Java 8Java 8 is the next largest Java 7 upgrade, which has some important features and enhancements in the Java model. JVM supports dynamic languages plus minor language improvements are one of the most notable features of Java's 7.
Java 8 also gets a new and improved Date/Time API, an enhanced JavaScript engine, new streaming API. Concurrent accumulators, secure random generation, and much more. Java 7 had improved class-loader architecture, enhanced Managed Beans, multiple exceptions handling support, etc.
Java SE 8 is binary-compatible with Java SE 7 except for the incompatibilities listed below. Except for the noted incompatibilities, class files built with the Java SE 7 compiler will run correctly in Java SE 8. Class files built with the Java SE 8 compiler will not run on earlier releases of Java SE.
String.valueOf
is a heavily overloaded method and you are using it in a context where the argument type must be inferred from the context. On the other hand, the rules of type inference have received a significant overhaul in Java 8; most notably target type inference has been much improved. So, whereas before Java 8 the method argument site did not receive any inference, defaulting to Object
in your case, in Java 8 the most specific applicable type was inferred, in this case char[]
.
However, keep in mind that in both cases the idiom you used is essentially broken so the change in compiler output should perhaps be designated as a "pitfall", but not a "bug".
The unchecked cast is unfortunately sometimes unavoidable, but I can't think of any case where it makes sense to infer the type itself (as opposed to a type parameter) of something which is not created reflectively from a Class
object. Therefore you are not likely to actually find yourself in the position shown here, where you infer the type based on the acceptable argument types on the call site. Moreover, it is certainly broken to do this with an overloaded method, leaving the choice of argument type to inference. This can only work "by accident".
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