[英]Self-referential Generic Types
考虑这个例子:
public final class Main<T extends Main<T>> {
public static void main(String[] args) {
Main<?> main = new Main<>();
}
}
这完全编译。 但是当我尝试在不使用菱形的情况下进行编译时,我能够使用它的唯一方法是使用原始类型。
Main<?> main = new Main();
没有原始类型的尝试不起作用:
Main<?> main = new Main<?>(); // None of
Main<?> main = new Main<Main<?>>(); // these
Main<?> main = new Main<Main<Main<?>>>(); // compile
那么为什么钻石的原始版本有效呢? 当您编写Main<?> main = new Main<>();
时,推断类型是什么Main<?> main = new Main<>();
?
它是推断原始类型,还是推断某种无限嵌套类型?
Main<Main<Main<Main<...>>>>
的?
在Main<?>
是占位符,在绑定时可以是任何类型。
每个?
您在源代码中编写的内容可能是不同的类型(在错误消息中称为capture#2-of ?
),因此您无法将Main<?>
的表达式分配给任何可表达类型的变量。
钻石操作员在这里工作,因为它的类型推断在?
之后运行?
s被捕获 - 您的Main<>
变为Main<?>
但是Main<capture#1 of ?>
(假设您将其分配给Main<?>
是capture#1
)。
换句话说,菱形运算符是唯一可以直接指定特定捕获的语法,就像var
中的var
是唯一可以直接指定匿名类型的语法。 (请注意,使用方法类型推断的重载解析也可以解析为特定捕获)
至于代码的含义, new Main<?>()
(对于任何捕获?
)是Main<? extends Object>
缩写Main<? extends Object>
Main<? extends Object>
,或者,在您的情况下, Main<? extends Main<same ?>>
Main<? extends Main<same ?>>
(编译器自动将?
约束到类型的约束)。 这成为Main<>
的协变视图,其中type参数只能转换为Main<?>
(因为它实际上可能是任何类型,所以你不能假设超出约束的任何东西)。
通常,没有理由真正创造这样的东西。
通过使用通用的辅助方法,可以在没有菱形运算符的情况下编译一些东西(当然,这会引发一个问题,即调用辅助方法的类型参数是什么):
final class Main<T extends Main<T>> {
public static void main(String[] args) {
Main<?> main = helper();
}
private static <T extends Main<T>> Main<T> helper() {
return new Main<T>();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.