了解Java中的捕获类型(符号'?') [英] Understanding a captured type in Java (symbol '?')
问题描述
什么是?
。它与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 ofe1
ande2
are written exactly the same,Ex<?>
. Bute1
ande2
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
ande2
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 toInteger
.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屋!