Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
479 views
in Technique[技术] by (71.8m points)

generics - ClassCast error: Java 7 vs Java 8

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)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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".


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...