Java 为我揭开通配符的神秘面纱

Java 为我揭开通配符的神秘面纱,java,generics,wildcard,Java,Generics,Wildcard,为什么在这段代码上会出现编译时错误 public Interface Location { ....... } 类代码 Map<Type, List<? extends Location>> locationsTypeMap = new HashMap<Type, List<? extends Location>>(); /** Code to add elements to the hashMap. */ newLocat

为什么在这段代码上会出现编译时错误

public Interface Location {
 .......
}
类代码

 Map<Type, List<? extends Location>> locationsTypeMap = new HashMap<Type, List<? extends Location>>();
  /**
   Code to add elements to the hashMap.
  */
  newLocation = getNewLocation()
  while(mapHasElements){
    Location.Type key = location.getType();
    List<? extends Location> valueList = (List<? extends Location>)locationsTypeMap.get(key); //1
    valueList.add(newLocation);/*Compile error*/
  }
Map通配符“?扩展位置”意味着“对于某些
T
来说,我希望它是
List
,其中
T
Location
的子类(或者是
Location
本身)。”

现在,让我们暂时把它放在一边。您是否希望编译以下内容:

List<String> strings = new List<String>();
strings.add(new Object());
List strings=newlist();
添加(新对象());
??我不这么认为——你不能在字符串列表中添加一个简单的“对象”。字符串列表中的任何项都必须是字符串

回到你的第一件事。假设
locationsTypeMap.get(key)
返回一个对象,该对象(逻辑上-暂时忽略类型擦除)是
列表
,但假设newLocation实际上是
BoringLocation的一个实例
。您不应该将
BoringLocation
添加到
列表中,编译器知道这一点,因此它阻止了这种情况的发生


列表中获得的任何内容都是可为空的类型,如下所示:


编辑:鉴于以上两个答案,我一定错了!对不起

语言错误,与可空性无关。在C#中,这将是完全不正确的语法。我认为,在发布和编辑之后,我第一次在多语言论坛上发布了“对不起,新堆栈溢出”。因此,成员们早些时候为我澄清了这个确切的情况。虽然您已经接受了答案,但您可能仍然想检查一下:编译器应该警告您强制转换不安全,(List)将编译为(List),如果列表是列表,则不会引发类强制转换异常,如果插入对象,则可能会导致代码的其他部分出现类强制转换异常
List<String> strings = new List<String>();
strings.add(new Object());