繁体   English   中英

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

[英]Generics - Why don't some versions work?

此代码取自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");
}

您需要问的是编译器是否可以确定 list的元素类型是否与String一致:

  1. <?> - 类型未知。 例如,它可能是Integer 我们不知道String适合。 new List<Integer>().add("quack")不会编译,所以这也不能。
  2. <? extends Object> <? extends Object> - 再次,类型未知。 所有类都扩展了Object 所以它也可能是Integer
  3. <Object> - 这里没有泛型。 StringObject的子类。 new List<Object>().add("quack")有效,所以这个编译。
  4. <? super String> <? super String>这是未知的,条件(“ bounds ”)表示它是String的超类。 由于我们知道String extends Object ,因此这种类型只能是ObjectString List<Object>().add("quack")List<String>().add("quack") ,所以这个编译。

数字4的推理当然适用于更复杂的类型层次结构:

BufferedInputStream扩展FilterInputStream扩展InputStream扩展Object InputStream实现了CloseableAutoCloseable接口。

那么<? super FilterInputStream> <? super FilterInputStream>匹配ObjectInputStreamFilterInputStreamCloseableAutoCloseable

List<? super FilterInputStream> l List<? super FilterInputStream> l可以是List<Closeable> ,也可以是List<InputStream >等等。但是你所知道的是你可以l.add(new FilterInputStream())或者,因为它是l.add(new BufferedInputStream())的子类l.add(new BufferedInputStream())

在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也不起作用。 有关通用边界,请参阅此答案

暂无
暂无

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

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