什么是Java中的捕获转换,谁能给我举例?

时间:2010-12-13 17:38:32

标签: java capture jls

我注意到5.1.10 Capture Conversion的JLS谈话,但我不明白它们是什么。

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

2 个答案:

答案 0 :(得分:20)

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

假设我们有以下类:

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

}

我们的代码就在某处,

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

由于test不是原始Test,并且“hindsight”中的repeatPreviousShout()返回?,因此编译器知道有T提供服务作为Test的类型参数。 此T用于某些未知T,因此编译器会删除未知类型(对于通配符,它​​将替换为Object)。因此repeatPreviousShout()将返回Object

但如果我们有,

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

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

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

来自here (Java theory and practice: Going wild with generics, Part 1),它明确指出:

  

捕获转换是允许的   编译器来制作占位符   捕获的通配符的类型名称,   所以类型推断可以推断它   是那种类型。

希望这会对你有所帮助。

答案 1 :(得分:1)

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

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

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

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

缩小表达式的类型。如果表达式的类型是List<? extends Number>,我们肯定知道对象的运行时类型对于某些具体类型S(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 :< B其中A涉及通配符参数。例如,

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

因此,我们正在检查捕获的A

类型的版本