为什么 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
.
所有基本类型、Object
和 String
都有 PrintStream.println
的重载。这大概是为了避免在已知打印的值是 String
.
时额外调用 Object.toString
所以想象一下生成的字节码对于两次调用 println
:
会是什么样子
Integer integerVal = 4;
rawBox.setValue(integerVal);
System.out.println(intBox.getValue());
在这种情况下,intBox.getValue()
returns Object
,因此我们将调用接受 Object
的 println
版本。编译器知道 return 值应该是 Integer
,但这并不重要,因为没有接受 Integer
.[=36= 的 println
重载]
System.out.println(stringBox.getValue());
这里,虽然stringBox.getValue()
returns Object
,编译器知道它应该是一个String
,想要调用println
的版本接受 String
。这需要将 return 值向下转换为 String
,这会失败,因为它实际上是一个 Integer
.
这个问题也可以看做:为什么一个泛型的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
.
所有基本类型、Object
和 String
都有 PrintStream.println
的重载。这大概是为了避免在已知打印的值是 String
.
Object.toString
所以想象一下生成的字节码对于两次调用 println
:
Integer integerVal = 4;
rawBox.setValue(integerVal);
System.out.println(intBox.getValue());
在这种情况下,intBox.getValue()
returns Object
,因此我们将调用接受 Object
的 println
版本。编译器知道 return 值应该是 Integer
,但这并不重要,因为没有接受 Integer
.[=36= 的 println
重载]
System.out.println(stringBox.getValue());
这里,虽然stringBox.getValue()
returns Object
,编译器知道它应该是一个String
,想要调用println
的版本接受 String
。这需要将 return 值向下转换为 String
,这会失败,因为它实际上是一个 Integer
.