这个问题在这里已经有答案了:
为什么数组是协变的而泛型是不变的(9个答案)
上个月关门了。
我找不到一个更好的描述我的问题的主题,所以我会尽量更好地解释我的问题。我注意到,如果我使用有界通配符,我可以使用它的“绑定”作为参数,但不能作为返回值。这听起来可能很混乱,所以我会直接粘贴代码。
public static void main (String[] args) {
List<?> wildcardList = new ArrayList<> ();
List<String> stringList = new ArrayList<> ();
takeList (wildcardList); //compiles
takeList (stringList); //compiles
/////////////////////////////////////
List<?> wildcard = returnList (); //compiles
List<String> strings = returnList (); //doesn't compile
}
static void takeList(List<? extends Object> list){
//some code
}
static List<? extends Object> returnList(){
return new ArrayList<> ();
}
我想知道为什么最后一行代码不能编译。当我显式地说 returnList()
是否<?扩展对象>。很明显,弦是一个物体。有人能帮我把这个弄清楚吗?
1条答案
按热度按时间wn9m85ua1#
让我们关注两条线:
以防万一
a
,没有错误,作为List<? extends Object>
正是一个List<?>
.以防万一
b
,java编译器*的问题是,如果允许赋值,是否会生成任何类型的意外错误(类转换)。让我们看一些例子:f()实际上返回一个列表(
List<String>
is-a公司List<? extends Object>
)--没问题f()实际上返回一个列表(
List<Integer>
is-a公司List<? extends Object>
)--会导致问题,就像现在一样b
被认为是List<String>
,但是b.add("foo")
就会失败。编译器有理由担心您可能使用不当。是的,它可以让你继续检查,确实,你没有打电话
b.add()
--但这会使编译器复杂化,而没有什么好处。还有很多地方可以通过验证不会发生任何不好的事情来避免编译错误,但是使用简单的规则(“除非显式抛出,否则没有风险”)可以使规则更容易遵循,默认为“只允许安全的事情”是java语言的一部分。要比较:
(*)-我在广义上使用“编译器”,指的是语言和编译器。