了解Java中的捕获类型(符号'?') [英] Understanding a captured type in Java (symbol '?')

查看:122
本文介绍了了解Java中的捕获类型(符号'?')的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是。它与Java编译器的实现细节有关,或者类型在 JLS 。例如,

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

public class RecipientSetType extends RecipientType {

public Integer accept(RecipientTypeVisitor<> visitor){//错误:
return visitor。参观(本); //无法将#1的捕获转换为整数
}
}

但是如果我们这样写:

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

public class RecipientSetType extends RecipientType {

public Object accept(RecipientTypeVisitor<> visitor){// OK:
return visitor。参观(本); //这意味着#1的捕获是
//作为Java中的任何引用类型的对象的子类型。


$ / code $ / pre

这就是我可以说的关于被捕获的类型。那么它究竟是什么?

解决方案

捕获通配符类型是编译器使用的类型,表示通配符的特定实例的类型例如:以两个通配符参数 void m(Ex <?> e1, Ex<> e2)< / code> ;.声明的类型 e1 e2 完全相同, Ex <?> 。但是 e1 e2 可能具有不同的和不兼容的运行时类型。



类型检查器不得将相同的类型考虑在内,即使它们的写法相同。因此,在编译过程中, e1 e2 的类型参数被赋予特定的类型,每个地方使用新的类型参数。这些新类型被称为它们声明类型的 capture



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



对此的技术描述可以在 JLS


5.1.10。捕获转换

设G用n个类型参数A1,...,A命名一个泛型类型声明(§8.1.2,§9.1.2),并带有相应的边界U1 ,...,Un。

存在从参数化类型G(§4.5)到参数化类型G的捕获转换,其中对于1≤i≤n :


  • 如果Ti是形式为?的通配符参数(§4.5.1),那么Si是一个新鲜的类型变量,它的上绑定是Ui [A1:= S1,...,An:= Sn],其下限是空类型(§4.1)。
  • ...
  • $

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

  public Integer accept(RecipientTypeVisitor<?> visitor){//错误:
return visitor.visit(this); //无法将#1的捕获转换为整数
}

捕获类型参数编译期间引入了 RecipientTypeVisitor 。被捕获的类型参数是具体但完全未知的(JLS称它为新鲜类型变量),当然不能转换为整数



无法直接表示捕获通配符类型,因此您无法声明该类型的变量或使用该类型的变量。您可以通过调用一个通用方法作为参数来间接获取它的名称。我引用的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));
}
}



What is ?. Is it related to implementation details of the Java compiler or the type is defined in the JLS.

For instance,

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
    }
}

But if we write this:

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.
    }
}

That's all I can say about a captured type. So what is it actually?

解决方案

The capture of a wildcard type is a type that is used by the compiler represent the type of a specific instance of the wildcard type, in one specific place.

Example: Take for example a method with two wildcard parameters, void m(Ex<?> e1, Ex<?> e2). The declared types of e1 and e2 are written exactly the same, Ex<?>. But e1 and e2 could have different and incompatible runtime types.

The type checker must not consider the types equal even if they are written the same way. Therefore, during compilation the type parameters of e1 and e2 are given specific types, new ones for each place they are used. These new types are called the capture of their declared types.

The capture of a wildcard is an unknown, but normal and concrete type. It can be used the same way as other types.

A technical description of this can be found in the 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).
  • ...

We can apply this to your example:

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

A capture of the type parameter of RecipientTypeVisitor is introduced during compilation. The captured type parameter is concrete but totally unknown (the JLS calls this a "fresh type variable"), and certainly not convertible to Integer.

There is no way to denote the capture of a wildcard type directly, so you can't declare variables of that type or do much with it. You can however get a name for it indirectly by calling a generic method with it as a parameter. The JLS section I cited has a nice example of this further down:

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中的捕获类型(符号'?')的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆