代码之家  ›  专栏  ›  技术社区  ›  skip

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

  •  3
  • skip  · 技术社区  · 7 年前

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

    BackLister :

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

    // INSERT HERE 类来编译和运行而不出错?

    以下是选项:

    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 选项正确吗?

    我明白以下几点:

    1. public static <T> List<? extends T> backwards(List<T> input) List 属于 T型 或子类 T型 .
    2. public static <T> List<? super T> backwards(List<T> input) 意味着返回类型应该是 列表 属于 或 超类 .

    3 回复  |  直到 7 年前
        1
  •  2
  •   Amin    7 年前

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

    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> 然后回来 列表<T> 你不能派 listApple 然后回来 listRedApple RedApple 因为它延伸了 Apple 但列表类型必须是 List<Apple> 其他都没有)

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

    苹果 苹果 但你知道 "? 扩展苹果” 因此在方法体中,java将T识别为Apple。然后如果使用可以在 作为参数发送,您可以添加 苹果 在里面 这不是真的!!!所以编译器会避免它并给出编译错误。在B你只能 读取元素 (以T表示)但不能添加任何内容。

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

    苹果 然后在方法体中可以添加任何扩展 因为编译器把T看作 苹果 在一个列表中 ,可以添加任何扩展 .
    但是这次,你不能读任何东西,因为你不知道它的类型,除非你得到它 Object )

    ? 延伸

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

    如果你派 然后你回来 List<? extends Apple> 但你可以把它分配给 listFood 苹果 因为 列表<?扩展Apple> 苹果 或者别的什么我们不能把它分配给任何人 列表<T> T 可能还有 ? extends T 不一样。两者都一样 D E 列表<?扩展Apple> List<? super Apple> 对于 并将它们发送到需要它们作为参数的方法。

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

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

    我希望这对你有帮助。

        2
  •  2
  •   Oleksandr Pyrohov Andreas    7 年前

    选项 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 表示(属于 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));
    

    因为类型 是通配符 ? super Long 表示(属于 以及类型

    所以,你的理解是正确的。

    Further reading

        3
  •  1
  •   A_C    7 年前

    下图描述了泛型中的子类型关系:

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

    enter image description here

    您可以参考以下页面: https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html