简体   繁体   English

返回类型为Java Generic方法的上限和下限通配符

[英]Upper-Bounded and Lower-Bounded Wildcards in return type of Java Generic method

I was trying to solve a problem where I am not able to understand part of the answer. 我试图解决一个我无法理解部分答案的问题。

Following is the class BackLister : 以下是BackLister类:

public class BackLister {
    // INSERT HERE
    {
        List<T> output = new LinkedList<T>();
        for (T t : input)
            output.add(0, t);
        return output;
    }
}

The question asks which can be inserted at // INSERT HERE in the BackLister class to compile and run without error? 这个问题询问哪些可以插入// INSERT HERE// INSERT HERE插入BackLister类来编译和运行而没有错误?

Following are the options: 以下是选项:

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)

I understand that that A and B are correct, as for for (T t : input) to work the elements in input should be of type T or subtype of T . 据我所知,A和B是正确的,作为用于for (T t : input)的工作中的元素input应类型的T或亚型T

But I am not able to understand why D and E options are correct? 但我无法理解为什么DE选项是正确的?

I understand the following: 我理解以下内容:

  1. public static <T> List<? extends T> backwards(List<T> input) public static <T> List<? extends T> backwards(List<T> input) means that the return type should be a List of T or subclass of T . public static <T> List<? extends T> backwards(List<T> input)意味着返回类型应该是一个ListT或子类T
  2. public static <T> List<? super T> backwards(List<T> input) public static <T> List<? super T> backwards(List<T> input) means that the return type should be a List of T or superclass of T . public static <T> List<? super T> backwards(List<T> input)意味着返回类型应该是一个ListT的或超类T

Could somebody help me understand it? 有人可以帮我理解吗?

There is difference between each of them and I'm going to explain most of them. 每个人之间都存在差异,我将解释他们中的大多数。 Let's start with our example. 让我们从我们的例子开始。 I use this class hierarchy: 我使用这个类层次结构:

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<>();

ow start with first one: 从第一个开始:

A. public static <T> List<T> backwards(List<T> input)

This method will only accept List<T> and return List<T> and you can not send listApple and return listRedApple . 此方法仅接受List<T>并返回List<T> ,您无法发送listApple并返回listRedApple (however your return list can contain RedApple because it extends Apple but type of list must be List<Apple> and nothing else) (但是你的返回列表可以包含RedApple因为它扩展了Apple但列表的类型必须是List<Apple>而没有别的)

B. public static <T> List<T> backwards(List<? extends T> input)

You can send listRedApple and return listApple but you know that listRedApple is "? extend Apple" so in the method body java recognize T as Apple. 您可以发送listRedApple并返回listApple但是您知道listRedApple“?extend Apple”所以在方法体java中将T识别为Apple。 Then if you use can add elements in listRedApple which sent as argument, you can add Apple in listRedApple which is not true!!! 然后如果你使用可以在listRedApple中添加作为参数发送的元素,你可以在listRedApple中添加Apple ,这不是真的! so compiler avoid it and give compile error. 所以编译器避免它并给出编译错误。 In B you can only read elements (and get it as T) but you can not add anything to it. 在B中,您只能读取元素 (并将其作为T),但您无法添加任何内容。

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

You can send listApple and then in method body you can add anything extends Apple because compiler see T as Apple and in a list of anything which is super of T , you can add anything extends Apple . 您可以发送listApple ,然后在方法体中,您可以添加任何扩展Apple因为编译器将T视为Apple并且在任何超级T的列表中,您可以添加任何扩展Apple
However this time, you can not read anything because you don't know its type except you get it as Object . 但是这一次,你不能阅读任何东西,因为你不知道它的类型,除非你把它作为Object (It is a list of "? super T" ) (这是“超级T”的清单)

As you see here there is difference between ? 正如你在这里看到的那样有区别 super and ? 超级 extend . 延伸 one of them give you write access and other give you read access. 其中一个给你写访问权限,其他给你读取权限。 This is the real use of wildcard. 这是通配符的真实用途。

D. public static <T> List<? extends T> backwards(List<T> input)
E. public static <T> List<? super T> backwards(List<T> input)   

If you send listApple then you return List<? extends Apple> 如果你发送listApple然后你返回List<? extends Apple> List<? extends Apple> but you can's assign it to any of listFood or listApple or listRedApple because List<? extends Apple> List<? extends Apple>但您可以将其分配给listFoodlistApplelistRedApple任何一个,因为List<? extends Apple> List<? extends Apple> maybe contain Apple or RedApple or something else and we can't assign it to any List<T> because then we can add T to that list and maybe T and ? extends T List<? extends Apple>可能包含AppleRedApple或其他东西,我们不能将它分配给任何List<T>因为那样我们可以将T添加到该列表中,也许T? extends T ? extends T is not same. ? extends T不一样。 this is same for both D and E . DE都是一样的。 You can assign it to List<? extends Apple> 你可以将它分配给List<? extends Apple> List<? extends Apple> for 'E and List<? super Apple> List<? extends Apple>为'E和List<? super Apple> List<? super Apple> for D and send them to a method which need them as parameter. 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)

Give compile errors because wildcard can not used like this. 给出编译错误,因为通配符不能像这样使用。

I hope this help you. 我希望这对你有帮助。
If something is wrong, any comment is appreciated. 如果出现问题,任何评论都表示赞赏。

Options D and E are valid because there exist a super-subtype relationships among generic types that allow you to define a larger set of types that the method can accept or return. 选项DE是有效的,因为泛型类型之间存在超子类型关系,允许您定义方法可以接受或返回的更大类型集。

Consequently, the following is valid (D): 因此,以下内容有效(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));

because the type Long is a member of the type family that the wildcard ? extends Number 因为Long类型是通配符类型族的成员? extends Number ? extends Number denotes (the family of types that are subtypes of Number and the type Number itself). ? extends Number表示(的是亚型类型的家庭Number和类型Number本身)。

The next code snippet is also valid (E): 下一个代码段也有效(E):

public static <T> List<? super T> backwards(List<T> input) {
    return List.of();
}

List<? super Long> ints = backwards(List.<Long>of(1L, 2L));

because the type Long is a member of the type family that the wildcard ? super Long 因为Long类型是通配符类型族的成员? super Long ? super Long denotes (the family of types that are supertypes of Long and the type Long itself). ? super Long表示(家庭是的超类型类型Long和类型的Long本身)。

So, your understanding is correct. 所以,你的理解是正确的。

Further reading . 进一步阅读

Below image describes the sub-typing relation in Generics: 下图描述了泛型中的子类型关系:

List<T> is a subtype of List<? super T>
Also List<T> is a subtype of List<? extends T>

This is why options D and E are correct. 这就是选项D和E正确的原因。

在此输入图像描述

You can refer the page : https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html 您可以参考页面: https//docs.oracle.com/javase/tutorial/java/generics/subtyping.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM