为什么Integer的泛型未分配String的值,在打印时会发出错误?

问题描述 投票:2回答:1

该问题也可以看作:为什么在打印时为String的泛型分配了Integer的值?但是,该问题的答案似乎很明显,标题问题对我而言却不是。我不明白为什么一个错误而不是另一个错误。问题适用于此示例。假设您有一个参数化的Box类:

class Box <T> {
    T value;

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

    T getValue() {
        return value;
    }
}

并且您有该类的三个实例,一个实例没有类型参数,另外两个实例具有String或Integer。字符串和整数框被实例化为原始对象:

    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()时发出。因此,为什么实例化为原始类型的Integer类型参数的参数化对象可以通过原始引用为其通用类型分配String值,并且在打印getValue()时却没有运行时错误,但是如果相同的参数化类型具有String的类型参数,并且它的通用类型通过原始类型分配了Integer的值,当它的getValue()打印时,它将引发ClassCastException?

java generics classcastexception
1个回答
3
投票

您可能理解,Box.value在运行时是Object,因此Box.getValue必须返回Object

对于所有原始类型,PrintStream.printlnObjectString都有重载。据推测,这是为了避免在已知要打印的值为Object.toString时额外调用String

因此,想象一下两次调用println时生成的字节码是什么样的:

Integer integerVal = 4;
rawBox.setValue(integerVal);
System.out.println(intBox.getValue());

在这种情况下,intBox.getValue()返回Object,因此我们将调用接受printlnObject版本。编译器知道返回值应该为Integer,但这没关系,因为没有println的重载可以接受Integer

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

这里,stringBox.getValue()返回Object时,编译器知道它应该是String,并希望调用接受printlnString版本。这需要将返回值向下转换为String,该操作失败,因为它实际上是Integer

© www.soinside.com 2019 - 2024. All rights reserved.