java - 了解 Java 中的捕获类型(符号 '?')

标签 java generics

什么是。是否与 Java 编译器的实现细节有关或类型在 JLS 中定义? .

例如,

public interface RecipientTypeVisitor<ReturnType> {
    public ReturnType visit(RecipientSetType t);
}

public class RecipientSetType extends RecipientType{

    public Integer accept(RecipientTypeVisitor<?> visitor){ //Error:
        return visitor.visit(this);             //Cannot convert capture of #1 to Integer
    }
}

但是如果我们这样写:

public interface RecipientTypeVisitor<ReturnType> {
    public ReturnType visit(RecipientSetType t);
}

public class RecipientSetType extends RecipientType{

    public Object accept(RecipientTypeVisitor<?> visitor){ //Ok:
        return visitor.visit(this);             //this implies tha the capture of #1 is 
                                     //a subtype of Object as any refrence type in Java.
    }
}

关于捕获的类型,我只能说这些了。那么它到底是什么?

最佳答案

捕获的通配符类型是编译器使用的一种类型,在一个特定的地方表示通配符类型的特定实例的类型。

示例:以一个带有两个通配符参数的方法为例,void m(Ex<?> e1, Ex<?> e2) . e1 的声明类型和 e2写得一模一样,Ex<?> .但是e1e2可能具有不同且不兼容的运行时类型。

类型检查器不能认为类型相等,即使它们以相同的方式编写。因此,在编译期间 e1 的类型参数和 e2被赋予特定的类型,每个地方都有新的类型。这些新类型称为对其声明类型的捕获

通配符的捕获是未知的,但正常且具体的类型。它可以像其他类型一样使用。

可以在 JLS 中找到对此的技术说明。 :

5.1.10. Capture Conversion

Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds U1,...,Un.

There exists a capture conversion from a parameterized type G (§4.5) to a parameterized type G, where, for 1 ≤ i ≤ n :

  • If Ti is a wildcard type argument (§4.5.1) of the form ?, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).
  • ...

我们可以将其应用于您的示例:

public Integer accept(RecipientTypeVisitor<?> visitor){ //Error:
    return visitor.visit(this);             //Cannot convert capture of #1 to Integer
}

捕获 RecipientTypeVisitor 的类型参数在编译期间引入。捕获的类型参数是具体的但完全未知(JLS 称其为“新类型变量”),当然不能转换为 Integer .

没有办法直接表示对通配符类型的捕获,因此您不能声明该类型的变量或对其做很多事情。但是,您可以通过以它作为参数调用泛型方法来间接为其命名。我引用的 JLS 部分有一个很好的例子:

public static void reverse(List<?> list) { rev(list); }
private static <T> void rev(List<T> list) {
    List<T> tmp = new ArrayList<T>(list);
    for (int i = 0; i < list.size(); i++) {
        list.set(i, tmp.get(list.size() - i - 1));
    }
}

关于java - 了解 Java 中的捕获类型(符号 '?'),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30797805/

相关文章:

java - 为什么 CF UAA check_token 端点需要 clientId/clientSecret?

JBoss 和 Quartz 上的 Java 堆空间停止运行

scala - 重载通用 scala 类中的构造函数

c# - 调用泛型方法的类型数组

java - 如何将泛型添加到我的代码中

java - "Attempting to use incompatible return type"具有实现可序列化的类

java - SQL 查询生成器实用程序

java - 如何将字符串值转换为整数数组列表 - Android

java - 确定二级缓存是否在 hibernate 中工作的问题

java - 为什么我应该优先使用通配符而不是类型参数?