gpt4 book ai didi

Java - 获取泛型对象作为 String 泛型类型抛出异常

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:19:52 27 4
gpt4 key购买 nike

public class Box<T> {
private T element;

public T getElement() {
return element;
}

public void setElement(T element) {
this.element = element;
}
}

public class Test {

public static void main(String[] args) {
List<Box> l = new ArrayList<>(); //Just List of Box with no specific type
Box<String> box1 = new Box<>();
box1.setElement("aa");
Box<Integer> box2 = new Box<>();
box2.setElement(10);

l.add(box1);
l.add(box2);

//Case 1
Box<Integer> b1 = l.get(0);
System.out.println(b1.getElement()); //why no error

//Case 2
Box<String> b2 = l.get(1);
System.out.println(b2.getElement()); //throws ClassCastException

}
}

列表l持有 Box 类型的元素.在情况 1 中,我得到的第一个元素为 Box<Integer>在第二种情况下,列表中的第二个元素获得为 Box<String> .在第一种情况下不会抛出 ClassCastException。

当我尝试调试时,element's输入 b1b2StringInteger分别。

和类型删除有关吗?

Ideone link

最佳答案

准确的说,问题是PrintStream#println .

让我们使用 javap -c Test.class 检查编译后的代码:

72: invokevirtual #12        // Method blub/Box.getElement:()Ljava/lang/Object;
75: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V

如您所见,编译器删除了类型并省略了 Integer 的转换。 ,因为这里没有必要。编译器已经将使用过的重载方法链接到 PrintStream#(Object) .它这样做是由于 JLS rule §5.3 :

Method invocation conversion is applied to each argument value in a method or constructor invocation (§8.8.7.1, §15.9, §15.12): the type of the argument expression must be converted to the type of the corresponding parameter.

Method invocation contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)
  • a widening primitive conversion (§5.1.2)
  • a widening reference conversion (§5.1.5)
  • a boxing conversion (§5.1.7) optionally followed by widening reference conversion
  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

第三条规则是从子类型到父类(super class)型的转换:

A widening reference conversion exists from any reference type S to any reference type T, provided S is a subtype (§4.10) of T.

并且在检查类型是否可以拆箱之前完成(第五次检查:“拆箱转换”)。所以编译器检查 IntegerObject 的子类型因此它必须调用 #println(Object) (如果您检查调用的重载版本,您的 IDE 会告诉您相同的信息)。

另一方面,第二个版本:

 95: invokevirtual #12        // Method blub/Box.getElement:()Ljava/lang/Object;
98: checkcast #14 // class java/lang/String
101: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

有一个checkcast检查检索到的类型 Box#getElement真的是String .这是必要的,因为您告诉编译器它将是 String (由于通用类型 Box<String> b2 = l.get(1); )并且它链接了方法 PrintStream#(String) .此检查因提到的 ClassCastException 而失败,因为 Integer无法转换为 String .

关于Java - 获取泛型对象作为 String 泛型类型抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36233351/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com