java - Java泛型方法返回类型中的上界和下界通配符

标签 java generics wildcard 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 处可以插入哪个在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 的子类型.

但我无法理解为什么DE选项是否正确?

我了解以下内容:

  1. public static <T> List<? extends T> backwards(List<T> input) 意味着返回类型应该是 ListT或子类 的 T .
  2. public static <T> List<? super T> backwards(List<T> input)意味着返回类型应该是 ListT或者 T 的父类(super class).

谁能帮我理解一下?

最佳答案

它们之间各有不同,我将解释其中的大部分。让我们从我们的例子开始。我使用这个类层次结构:

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 中添加元素作为参数发送的,您可以添加 ApplelistRedApple这不是真的!所以编译器避免它并给出编译错误。在 B 中,您只能读取元素(并将其作为 T 获取),但不能向其中添加任何内容。

C. public static <T> List<T> backwards(List<? super T> input) 

您可以发送listApple然后在方法主体中,您可以添加任何扩展 Apple因为编译器将 T 视为 AppleT 的 super 元素 列表中,您可以添加任何扩展 Apple .
但是这一次,您无法读取任何内容,因为您不知道它的类型,除非您将其作为 Object 获取。 . (是"?super T"的列表)

如您所见, 之间有区别吗? super ?延伸。其中一个为您提供写入权限,另一个为您提供读取权限。这才是通配符的真正用途。

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>但你可以将它分配给任何 listFoodlistApplelistRedApple因为List<? extends Apple>可能包含 AppleRedApple或其他东西,我们无法将其分配给任何 List<T>因为这样我们就可以添加 T到那个名单,也许T? extends T不一样。这对于 D 都是一样的和 E .您可以将其分配给 List<? extends Apple>对于 'E 和 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)

给出编译错误,因为不能这样使用通配符。

希望对你有帮助。
如果有什么不对,欢迎提出任何意见。

关于java - Java泛型方法返回类型中的上界和下界通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53010162/

相关文章:

regex - 通配符的行为是否有所不同?

java - 如何在单元测试中处理模拟的 RxJava2 可观察抛出异常

java - 使用 Java 和 awt.Robot 时提高屏幕捕获速度

algorithm - 如何在 Scala 中定义一个采用 Ordered[T] 数组的方法?

c# - 泛型类中有歧义/冲突的构造函数

c# - 我可以创建一个 List<WeakReference<T>> 吗?

java - 如何防止具体类的实例化?

java - 继承中的方法签名

java - 在 Java 中,为什么数组不能是类型变量的边界,但可以是通配符的边界?

windows - Windows 批处理命令中目录的通配符