<! - ?的区别在方法和变量声明中超级/扩展String - >

时间:2014-07-21 09:30:43

标签: java generics collections extends super

假设:

import java.util.*;

public class Hancock {
    //insert code here
        list.add("foo");
    }
}

在第5行独立插入的两个代码片段将在没有警告的情况下编译? (选择两项)

A. public void addString(List list) {
B. public void addString(List<String> list) {
C. public void addString(List<? super String> list) {
D. public void addString(List<? extends String> list) {

正确答案是B&amp;下进行。

答案A和B对我来说非常清楚。对于答案C&amp;我知道继承的方式是什么,但是我无法理解为什么答案D不会在Eclipse中编译而其他所有人都这样做(A有关于通用的警告,B&amp; C没有warrings)。

Eclipse中答案D的错误是The method add(capture#1-of ? extends String) in the type List<capture#1-of ? extends String> is not applicable for the arguments (String)

另一方面,这编译:

public void addString() {
    List<? extends String> list1 = new ArrayList<String>();
    List<? super String> list2 = new ArrayList<String>();
}

为什么呢?为什么<? super String>在变量声明中编译时不会在方法声明中编译。

我知道String是最后一堂课,不能被任何其他班级扩展,但这并没有向我解释这里发生了什么。

2 个答案:

答案 0 :(得分:9)

首先,让我们看一下答案C:

public void addString(List<? super String> list) {
    list.add("foo");
}

此方法声明表示您将被允许传递List个对象,这些对象由某些超级String参数化,例如StringObject。所以:

  1. 如果您通过List<String>,则list.add("foo")将完全有效。
  2. 如果您通过List<Object>,则list.add("foo")将完全有效,因为&#34; foo&#34;是String(您可以将String添加到List<Object>)。
  3. 这意味着答案C是正确的。


    现在让我们看看答案D.

    如果你有这样的方法声明:

    public void addString(List<? extends String> list) {
    
    }
    

    这意味着您将能够传递List 某些未知子类型String参数化的对象。因此,当您执行list.add("foo");时,编译器不会意识到所提供的对象是否具有与String unknown 子类型匹配的类型,因此会引发编译 - 时间错误。


    当你有:

    public void addString() {
        List<? extends String> list1 = new ArrayList<String>();
        List<? super String> list2 = new ArrayList<String>();
    }
    

    此片段编译得很好,因为list1被定义为保存List某些未知子类型的String对象,包括String本身,这就是为什么它#39;有效。 问题是,您无法添加任何内容null除外。

    对于list2,变量可以容纳List个对象,这些对象由某些超类型String参数化,包括String本身。


    更多信息:

答案 1 :(得分:2)

首先,仿制药并不关心String是最终的。它们对最终和非最终课程的工作方式相同。

考虑到这一点,应该明白为什么不允许D - 如果是,你可以这样做:

void test() {
    List<Integer> integers = new ArrayList<Integer>();
    addADouble(integers);
    int a = integers.get(0); // ????
}

void addADouble(List<? extends Number> list) {
    list.add(new Double(5.0));
}

List<? extends Number>是一个扩展数字的内容列表,但您并不确切知道它的列表是什么。&#34; - 它可能是List<Double>List<Integer>List<Number>List<YourCustomSubclassOfNumber>,因此您无法添加任何内容,因为您没有&# 39;不知道它是否是正确的类型。