[英]Upper-Bounded and Lower-Bounded Wildcards in return type of Java Generic method
我试图解决一个我无法理解部分答案的问题。
以下是BackLister
类:
public class BackLister {
// INSERT HERE
{
List<T> output = new LinkedList<T>();
for (T t : input)
output.add(0, t);
return output;
}
}
这个问题询问哪些可以插入// INSERT HERE
在// INSERT HERE
插入BackLister
类来编译和运行而没有错误?
以下是选项:
A. public static <T> List<T> backwards(List<T> input)
B. public static <T> List<T> backwards(List<? extends T> input)
C. public static <T> List<T> backwards(List<? super T> input)
D. public static <T> List<? extends T> backwards(List<T> input)
E. public static <T> List<? super T> backwards(List<T> input)
F. public static <? extends T> List<T> backwards(List<T> input)
G. public static <? super T> List<T> backwards(List<T> input)
据我所知,A和B是正确的,作为用于for (T t : input)
的工作中的元素input
应类型的T
或亚型T
。
但我无法理解为什么D
和E
选项是正确的?
我理解以下内容:
public static <T> List<? extends T> backwards(List<T> input)
public static <T> List<? extends T> backwards(List<T> input)
意味着返回类型应该是一个List
的T
或子类T
。 public static <T> List<? super T> backwards(List<T> input)
public static <T> List<? super T> backwards(List<T> input)
意味着返回类型应该是一个List
的T
的或超类T
。 有人可以帮我理解吗?
每个人之间都存在差异,我将解释他们中的大多数。 让我们从我们的例子开始。 我使用这个类层次结构:
class Food {}
class Apple extends Food {}
class Orange extends Food {}
class RedApple extends Apple {}
List<Food> listFood = new ArrayList<>();
List<Apple> listApple = new ArrayList<>();
List<Orange> listOrange = new ArrayList<>();
List<RedApple> listRedApple = new ArrayList<>();
从第一个开始:
A. public static <T> List<T> backwards(List<T> input)
此方法仅接受List<T>
并返回List<T>
,您无法发送listApple
并返回listRedApple
。 (但是你的返回列表可以包含RedApple
因为它扩展了Apple
但列表的类型必须是List<Apple>
而没有别的)
B. public static <T> List<T> backwards(List<? extends T> input)
您可以发送listRedApple
并返回listApple
但是您知道listRedApple
是“?extend Apple”所以在方法体java中将T识别为Apple。 然后如果你使用可以在listRedApple
中添加作为参数发送的元素,你可以在listRedApple
中添加Apple
,这不是真的! 所以编译器避免它并给出编译错误。 在B中,您只能读取元素 (并将其作为T),但您无法添加任何内容。
C. public static <T> List<T> backwards(List<? super T> input)
您可以发送listApple
,然后在方法体中,您可以添加任何扩展Apple
因为编译器将T视为Apple
并且在任何超级T的列表中,您可以添加任何扩展Apple
。
但是这一次,你不能阅读任何东西,因为你不知道它的类型,除非你把它作为Object
。 (这是“超级T”的清单)
正如你在这里看到的那样有区别? 超级和? 延伸 。 其中一个给你写访问权限,其他给你读取权限。 这是通配符的真实用途。
D. public static <T> List<? extends T> backwards(List<T> input)
E. public static <T> List<? super T> backwards(List<T> input)
如果你发送listApple
然后你返回List<? extends Apple>
List<? extends Apple>
但您可以将其分配给listFood
或listApple
或listRedApple
任何一个,因为List<? extends Apple>
List<? extends Apple>
可能包含Apple
或RedApple
或其他东西,我们不能将它分配给任何List<T>
因为那样我们可以将T
添加到该列表中,也许T
和? extends T
? extends T
不一样。 D
和E
都是一样的。 你可以将它分配给List<? extends Apple>
List<? extends Apple>
为'E和List<? super Apple>
List<? super Apple>
用于D
并将它们发送到需要它们作为参数的方法。
F. public static <? extends T> List<T> backwards(List<T> input)
G. public static <? super T> List<T> backwards(List<T> input)
给出编译错误,因为通配符不能像这样使用。
我希望这对你有帮助。
如果出现问题,任何评论都表示赞赏。
选项D
和E
是有效的,因为泛型类型之间存在超子类型关系,允许您定义方法可以接受或返回的更大类型集。
因此,以下内容有效(D):
public static <T> List<? extends T> backwards(List<T> input) {
return List.of();
}
// there exist a super-subtype relationships among List<? extends Number> and List<Long>
List<? extends Number> list = backwards(List.<Long>of(1L, 2L));
因为Long
类型是通配符类型族的成员? extends Number
? extends Number
表示(的是亚型类型的家庭Number
和类型Number
本身)。
下一个代码段也有效(E):
public static <T> List<? super T> backwards(List<T> input) {
return List.of();
}
List<? super Long> ints = backwards(List.<Long>of(1L, 2L));
因为Long
类型是通配符类型族的成员? super Long
? super Long
表示(家庭是的超类型类型Long
和类型的Long
本身)。
所以,你的理解是正确的。
进一步阅读 。
下图描述了泛型中的子类型关系:
List<T> is a subtype of List<? super T>
Also List<T> is a subtype of List<? extends T>
这就是选项D和E正确的原因。
您可以参考页面: https : //docs.oracle.com/javase/tutorial/java/generics/subtyping.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.