user4910279
user4910279

Reputation:

Why this program throws ClassCastException?

My program is

package stackoverflow;

public class Main {

    public static void main(String[] args) {
        String.valueOf(hoge());
    }

    static <E> E hoge() {
        return (E) "hoge";
    }

}

result is

Exception in thread "main" java.lang.ClassCastException: 
java.base/java.lang.String cannot be cast to [C
    at stackoverflow.Main.main(Main.java:6)

I'm using Java9. The return type of hoge is ambiguous. I think it should be compile error. And why compiler choose String.valueOf(char[]) instead of String.valueOf(Object)?

Upvotes: 0

Views: 291

Answers (2)

Erwin Bolwidt
Erwin Bolwidt

Reputation: 31269

When multiple overloaded methods are applicable for method resolution, the most specific method is chosen.

This can result in some odd behaviour if one of the argument types is generic and unrestricted, or null, because they match any declared method argument type.

In your case, char[] in valueOf(char[]) is more specific than Object in valueOf(Object) - that's the reason.

This is specified in JLS 15.12.2.5

Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The result of the section goes into detail how this is done.

java.lang.Object is not special in this respect; you'll get the same issue with the following code:

public class Main {

    private static String valueOf(Number x) {
        return null;
    }
    private static String valueOf(Integer x) {
        return null;
    }
    public static void main(String[] args) {
        valueOf(hoge());
    }

    static <E> E hoge() {
        return (E) "hoge";
    }

}

In the above case, the method call will go to valueOf(Integer) because Integer is more specific than Number.

Upvotes: 0

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 135992

There are several overloaded String.valueOfs, only two of them have object parameter valueOf(char[]) and valueOf(Object), others are primitive, like String.valueOf(int). Since exact return type is unknown, but it's an object type, compiler has chosen valueOf(char[]). I do not know which part of JLS explains that behavior, but it is similar to this:

public static void main(String[] args) {
    x(null);
}

static void x(char[] x) {
    System.out.println("char[]");
}

static void x(Object o) {
    System.out.println("Object");
}

compiler chooses char[]

Upvotes: 1

Related Questions