我找不到更好的问题主题描述,所以我会尽力更好地解释我的问题。我注意到,如果我使用有界通配符;绑定";作为参数,但不是返回值。这听起来可能令人困惑,所以我将立即粘贴我的代码。
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()
的返回类型是<时,这种情况下有什么问题;?扩展对象>。并且清楚地字符串IS-A对象。有人能帮我清理一下吗?
让我们关注两行:
// f() returns a List<? extends Object>
List<?> a = f(); // ok: can never do unexpected things
List<String> b = f(); // error: not 100% safe
对于情况a
,没有错误,因为List<? extends Object>
正是List<?>
。
对于案例b
,Java编译器*的问题是,如果允许执行赋值,是否会生成任何类型的意外错误(类转换(。让我们看看一些例子:
- f((实际上返回了一个List(
List<String>
是一个List<? extends Object>
(——没问题 - f((实际上返回了一个List(
List<Integer>
是一个List<? extends Object>
(——这可能会导致问题,因为现在b
被认为是List<String>
,但b.add("foo")
会失败
编译器理所当然地担心您可能使用不当。是的,它本可以让您检查是否确实没有调用b.add()
,但这会使编译器复杂化,几乎没有什么好处。在许多其他地方,通过验证实际不会发生任何错误,可以避免编译错误,但具有简单的规则("除非明确丢弃,否则没有风险"(会使规则更容易遵循,并且默认为";只允许安全的东西";在很大程度上是Java语言的一部分。
比较:
// f() returns a float
float a = f(); // ok
int b = f(); // error: not 100% safe, unwanted rounding may result!
(*(-我使用";编译器";从广义上讲,指的是语言和编译器。