Java中的捕获转换是什么,任何人都可以给我举个例子吗?

2022-09-02 01:21:14

我注意到JLS谈到5.1.10捕获转换,但我不明白它们是什么。

任何人都可以向我解释/举例吗?


答案 1

捕获转换旨在使通配符(在泛型中)有用。?

假设我们有以下类:

public interface Test<T> {
    public void shout(T whatever);
    public T repeatPreviousShout();

}

在我们的代码的某个地方,

public static void instantTest(Test<?> test) {
    System.out.println(test.repeatPreviousShout());
}

因为 不是原始的,并且由于在“事后看来”返回一个,编译器知道有一个作为 的类型参数。这是针对某些未知的,因此编译器会擦除未知类型(对于通配符,它将替换为 )。,因此返回 .testTestrepeatPreviousShout()?TTestTTObjectrepeatPreviousShout()Object

但是,如果我们有,

public static void instantTest2(Test<?> test) {
    test.shout(test.repeatPreviousShout());
}

编译器会给我们一个类似的东西的错误(其中是一个数字,例如)。Test<capture#xxx of ?> cannot be appliedxxx337

这是因为编译器尝试执行类型安全检查,但由于它收到了通配符,因此它不知道表示什么,因此它创建了一个名为 capture of 的占位符。shout()T

从这里开始(Java理论和实践:疯狂地使用泛型,第1部分),它清楚地指出:

捕获转换允许编译器为捕获的通配符构造占位符类型名称,以便类型推断可以推断出它是该类型。

希望这对您有所帮助。


答案 2

涉及通配符类型参数的参数化类型实际上是联合类型。例如

List<? extends Number> = Union{ List<S> | S <: Number }

在2种情况下,Java不使用,而是使用捕获的版本,其中S是刚刚创建的具有上限的类型变量。List<? extends Number>List<S>Number

(1) http://java.sun.com/docs/books/jls/third_edition/html/expressions.html

缩小表达式类型范围。如果表达式的类型是 ,我们可以肯定地知道,对于某些具体类型 S (),该对象的运行时类型实际上是 a。因此,编译器改用,来执行更准确的类型分析。List<? extends Number>List<S>S <: Number>List<S>

捕获转换分别应用于每个表达式;这导致了一些愚蠢的结果:

<T> void test1(List<T> a){}
<T> void test2(List<T> a, List<T> b){}

List<?> x = ...;
test1(x);    // ok
test2(x, x); // error

(2) http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.10.2

在子类型检查中,其中涉及通配符参数。例如A :< BA

List<? extends Number>  :< B
<=>
Union{ List<S> | S <: Number}  :< B
<=>
List<S> :< B, for all S <: Number

因此,实际上,我们正在检查捕获的类型版本。A


推荐