为什么这个程序抛出ClassCastException?

时间:2018-04-14 05:04:53

标签: java

我的节目是

package stackoverflow;

public class Main {

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

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

}

结果是

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

我正在使用Java9。 hoge的返回类型不明确。我认为应该是编译错误。 为什么编译器会选择String.valueOf(char[])而不是String.valueOf(Object)

2 个答案:

答案 0 :(得分:2)

有几个重载的String.valueOfs,其中只有两个具有对象参数valueOf(char [])和valueOf(Object),其他都是原始的,如String.valueOf(int)。由于确切的返回类型是未知的,但它是一个对象类型,编译器选择了valueOf(char [])。我不知道JLS的哪一部分解释了这种行为,但它与此类似:

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");
}

编译器选择char []

答案 1 :(得分:1)

当多个重载方法适用于方法解析时,选择了最具体的方法

如果其中一个参数类型是通用的且不受限制的,或者null,这会导致一些奇怪的行为,因为它们匹配任何声明的方法参数类型。

在您的情况下,char[]中的valueOf(char[])Object中的valueOf(Object)更具体 - 这就是原因。

这在JLS 15.12.2.5

中指定
  

选择最具体的方法

     

如果多个成员方法都可访问且适用于a   方法调用,有必要选择一个提供   运行时方法调度的描述符。 Java编程   language使用选择最具体方法的规则。

该部分的结果详细说明了如何完成。

java.lang.Object在这方面并不特别;您将在以下代码中遇到同样的问题:

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";
    }

}

在上述情况下,方法调用将转到valueOf(Integer),因为IntegerNumber更具体。