泛型 - 为什么某些版本不起作用?

时间:2017-10-11 08:35:38

标签: java generics

此代码取自OCP教科书。为什么addSound方法的版本1和版本2不能编译,但版本3和版本4编译?编译错误消息是" List中的add(capture)无法应用于java.lang.String"

public static void main(String[] args) {
    List<String> strings = new ArrayList<>();
    strings.add("tweet");
    List<Object> objects = new ArrayList<>(strings);
    addSound(strings);
    addSound(objects);
}

//version 1
public static void addSound(List<?> list) {
    list.add("quack");
}

//version 2
public static void addSound(List<? extends Object> list) {
    list.add("quack");
}

//version 3
public static void addSound(List<Object> list) {
    list.add("quack");
}

//version 4
public static void addSound(List<? super String> list) {
    list.add("quack");
}

2 个答案:

答案 0 :(得分:3)

您需要问的是,编译器是否某些 list的元素类型与String一致:

  1. <?> - 类型未知。例如,它可能是Integer。我们无法知道String适合。 new List<Integer>().add("quack")无法编译,因此也不能编译。
  2. <? extends Object> - 再次,类型未知。所有课程都延伸Object。所以它可能是Integer
  3. <Object> - 此处没有仿制药。 StringObject的子类。 new List<Object>().add("quack")有效,因此编译。
  4. <? super String>这是未知的,条件(“ bounds ”)表明它是String的超类。由于我们知道String extends Object,因此此类型只能是ObjectStringList<Object>().add("quack")没问题,List<String>().add("quack")没问题,所以编译。
  5. 第4号的推理当然适用于更复杂的类型层次结构:

    BufferedInputStream延伸FilterInputStream延伸InputStream延伸ObjectInputStream实现了接口CloseableAutoCloseable

    所以<? super FilterInputStream>匹配ObjectInputStreamFilterInputStreamCloseableAutoCloseable

    所以List<? super FilterInputStream> l可以是List<Closeable>,也可以是List<InputStream&gt;等等。但您确定知道的是l.add(new FilterInputStream())或者,因为它是一个子类l.add(new BufferedInputStream())

答案 1 :(得分:2)

在Java中,您有类型安全和类型擦除。这两个概念都是版本1和版本2不起作用的原因。

您无法向List<?>添加任何内容,因为您不知道列表中的对象类型。例如,它可能是IntegerString的列表。

public static void addSound(List<?> list) {
    list.add("quack"); // does not work since List<?> can be anything - type safety not guaranteed
}

Java编译器在运行时删除所有类型,称为类型擦除,例如List<String>ListList<Integer>也将List - 因此您无法区分它们。您可能会在字节码中看到它,但这与此无关。这就是版本2无法正常工作的原因

//version 2 - has the same type erasure as version 3
public static void addSound(List<? extends Object> list) {
    list.add("quack");
}

//version 3
public static void addSound(List<Object> list) {
    list.add("quack");
}

由于类型安全性,版本2也无法正常工作。请参阅generic bounds

的答案