没有中间变量,泛型代码无法编译

cod*_*box 2 java generics

我很惊讶main编译器允许下面的前两行代码。当我说即使签名也允许getIt()返回 a时,它似乎是信任我。DogCat

public class GenericsAreWeird {
    public static void main(String... args){
        // This is fine
        Dog d = getIt();
        d.woof();

        // This fails to compile
        // getIt().woof();

        // This compiles but gives a runtime ClassCastException
        Cat c = getIt();
        c.meow();
    }

    private static <T extends Animal> T getIt(){
        return (T) new Dog();
    }

    public static class Animal {}

    public static class Cat extends Animal{
        public void meow(){}
    }

    public static class Dog extends Animal{
        public void woof(){}
    }
}
Run Code Online (Sandbox Code Playgroud)

我通常相信 Java 泛型通过给出编译器错误来保护我免受 ClassCastExceptions 的影响,而不是在运行时告诉我某些东西不起作用,所以允许这似乎是坏事。

这似乎也违反直觉:

Dog d = getIt();
d.woof();
Run Code Online (Sandbox Code Playgroud)

不完全等同于:

getIt().woof();
Run Code Online (Sandbox Code Playgroud)

编译器需要中间变量作为“提示”。

泛型总是这样工作吗?有人可以向我指出(或提供)对编译器无法识别此类与类相关的错误的任何其他场景的正确解释吗?

luk*_*302 6

return (T) new Dog();在大多数情况下,告诉编译器
“关闭你的类型检查,我比你更了解这Dog将始终可分配给T
编译器回复
“好的,那么继续,然后你最好注意不要调用它期望它返回任何其他内容/一个Cat“的方法

然后你确实称它为期望它返回 aCat并得到一个应得的ClassCastException. 你会得到一个运行时异常,因为你告诉编译器你更了解它(你不知道)。