首页 > 解决方案 > Java Generic 方法的返回类型中的上界和下界通配符

问题描述

我试图解决一个我无法理解部分答案的问题。

以下是课程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应该TT.

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

我理解以下内容:

  1. public static <T> List<? extends T> backwards(List<T> input) 表示返回类型应该是ListofT或 的子类T
  2. public static <T> List<? super T> backwards(List<T> input)表示返回类型应该是ListofT或超类T

有人可以帮我理解吗?

标签: javagenericswildcardgeneric-method

解决方案


他们每个人之间都有区别,我将解释其中的大部分。让我们从我们的例子开始。我使用这个类层次结构:

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“?扩展 Apple”,因此在方法体中 java 将 T 识别为 Apple。然后,如果您使用可以添加listRedApple作为参数发送的元素,您可以添加不正确Apple的元素!!!listRedApple所以编译器避免它并给出编译错误。在 B 中,您只能读取元素(并将其作为 T 获取),但您不能向其中添加任何内容。

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

您可以发送listApple然后在方法主体中添加任何扩展Apple,因为编译器将 T 视为 TApple并且在T的超级列表中,您可以添加任何扩展Apple
但是这一次,您无法阅读任何内容,因为您不知道它的类型,除非您将其作为Object. (它是“?super 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>,但您可以将其分配给任何listFoodlistApple或,listRedApple因为List<? extends Apple>可能包含AppleRedApple或其他东西,我们不能将其分配给任何List<T>,因为这样我们可以添加T到该列表中,并且可能T并不? extends T相同。D这对于和都是一样的E。您可以将其分配给List<? extends Apple>for 'E 和List<? super Apple>forD并将它们发送到需要它们作为参数的方法。

F. public static <? extends T> List<T> backwards(List<T> input)
G. public static <? super T> List<T> backwards(List<T> input)

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

我希望这对你有帮助。
如果有什么问题,任何评论表示赞赏。


推荐阅读