为什么 Integer 的泛型分配了 String 的值在打印时没有发出错误?

Why doesn't a generic of Integer assigned a value of String issue an error when printed?

这个问题也可以看做:为什么一个泛型的String赋值了一个Integer在打印的时候会出现运行时间错误?但是这个问题的答案似乎很明显,标题问题对我来说却不是。我不明白为什么一个错误而不是另一个错误。这个问题适用于这个例子。假设您有一个参数化的 Box class:

class Box <T> {
    T value;

    void setValue(T value) {
        this.value = value;
    }

    T getValue() {
        return value;
    }
}

并且您有这个 class 的三个实例,一个没有类型参数,另外两个有 String 或 Integer。 String 和 Integer 的 Box 实例化为原始 object:

    Box rawBox = new Box();
    Box <Integer> intBox = rawBox;
    Box <String> stringBox = rawBox;

当我们通过原始引用传递 setValue() 值并通过各自的参数化引用打印 getValue() 时,我遇到的问题出现了:

    Integer integerVal = 4;
    rawBox.setValue(integerVal);
    System.out.println(intBox.getValue());
    // System.out.println(stringBox.getValue()); // ClassCastException a Integer cannot be assigned to a String

    rawBox.setValue("hi");
    System.out.println(intBox.getValue()); // Why is there no ClassCastException for assigning a String to Integer?
    System.out.println(stringBox.getValue()); 

ClassCastException 错误仅在打印 getValue() 时发出,而不是在调用 setValue() 时发出。那么为什么当 getValue() 是 Integer 的类型参数实例化到 rawtype 时,参数化 object 可以通过原始引用为其分配通用的 String 值并且没有 运行 时间错误打印但如果相同的参数化类型具有 String 的类型参数,并且它的泛型通过原始类型分配了 Integer 值,它会在打印 getValue() 时抛出 ClassCastException?

您可能明白 Box.value 在运行时是一个 Object,因此 Box.getValue 必须 return Object.

所有基本类型、ObjectString 都有 PrintStream.println 的重载。这大概是为了避免在已知打印的值是 String.

时额外调用 Object.toString

所以想象一下生成的字节码对于两次调用 println:

会是什么样子
Integer integerVal = 4;
rawBox.setValue(integerVal);
System.out.println(intBox.getValue());

在这种情况下,intBox.getValue() returns Object,因此我们将调用接受 Objectprintln 版本。编译器知道 return 值应该是 Integer,但这并不重要,因为没有接受 Integer.[=36= 的 println 重载]

System.out.println(stringBox.getValue());

这里,虽然stringBox.getValue() returns Object,编译器知道它应该是一个String,想要调用println的版本接受 String。这需要将 return 值向下转换为 String,这会失败,因为它实际上是一个 Integer.