gpt4 book ai didi

Java 泛型 "upcast"到非参数化类型

转载 作者:行者123 更新时间:2023-12-01 21:23:21 25 4
gpt4 key购买 nike

为什么只有在 Main.main() 中取消注释第三条语句时才会出现 ClassCastException ?没有异常(exception),但第一条和第二条语句执行得很好?

public class Tuple<K, V> {
public final K first;
public final V second;

public Tuple(K first, V second) {
this.first = first;
this.second = second;
}

@Override public String toString() {
return "Tuple{" + "first = " + first + ", second = " + second + '}';
}
}

class Test { static Tuple f(){return new Tuple("test", 8);} }

class Bar {}

class Main{
public static void main(String[] args) {
Tuple<String, Bar> t = Test.f();
System.out.println(t);
//System.out.println(t.second.getClass().getSimpleName());
}
}

提前致谢。

最佳答案

当您编写方法调用链时:

System.out.println(t.second.getClass().getSimpleName());

编译器有效地将其扩展为:

TypeOfTSecond tmpTSecond = t.second;
Class<?> clazzTmp = tmp.getClass();
String nameTmp = clazzTmp.getSimpleName();
System.out.println(nameTmp);

现在,如果 t.second 碰巧是泛型类型,编译器将插入一个转换为 t.second 将是的类型:

Bar tmpTSecond = (Bar) t.second;

因此,即使您从未访问任何 Bar 特定的功能,您也会收到 ClassCastException

<小时/>

为了演示这一点,这里是字节码:

  public static void main(java.lang.String[]);
Code:
0: invokestatic #2 // Method Test.f:()LTuple;
3: astore_1
4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_1
8: getfield #4 // Field Tuple.second:Ljava/lang/Object;
11: checkcast #5 // class Bar
14: invokevirtual #6 // Method java/lang/Object.getClass:()Ljava/lang/Class;
17: invokevirtual #7 // Method java/lang/Class.getSimpleName:()Ljava/lang/String;
20: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: return

第 8 行是将 t.second 压入堆栈的位置;第 11 行是转换为 Bar 的地方。

<小时/>

这只是因为声明 test.f() 时使用的原始类型而发生:

static Tuple f(){return new Tuple("test", 8);}

如果这被正确声明为

static Tuple<String, Integer> f(){return new Tuple<>("test", 8);}

然后这一行

Tuple<String, Bar> t = Test.f();

无法编译。但使用原始类型会禁用编译器的类型检查,因此不能保证防止此类运行时错误。

<小时/>

主要的外卖类(class)是 never use raw types .

第二个教训是注意编译器(或 IDE)的警告。编译这段代码时,我被告知:

Note: Main.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

当我使用该标志重新编译时:

Main.java:19: warning: [unchecked] unchecked call to Tuple(K,V) as a member of the raw type Tuple
return new Tuple("test", 8);
^
where K,V are type-variables:
K extends Object declared in class Tuple
V extends Object declared in class Tuple
Main.java:26: warning: [unchecked] unchecked conversion
Tuple<String, Bar> t = Test.f();
^
required: Tuple<String,Bar>
found: Tuple
2 warnings

关于Java 泛型 "upcast"到非参数化类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38775411/

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