从Raw到<? extends Object>

11

我就是不理解这个。

List list = new ArrayList();
List <? extends Object> list1 = list; // unchecked conversion warning.

由于在Java中,Object是最高的上限,我不明白为什么会有警告。

更新1:

关于akf的回答:

我完全理解你的意思。我已经知道了。 但是,? extends Object>是最高的上限。这意味着您可以拥有任何类型。基本上<?> == <? extends Object>

您可以在您的代码中尝试这个,您将看到<?> == <? extends Objects>

更新2:

关于Sheng的回答

List  list = new ArrayList ();
List.add("a");
List <? extends Runnable> list1 = list; //warning here

为什么这里没有警告?
List <?> list2 = list; // No warning here

更新3:

我正在重新审视以上内容,仍然感到困惑。

由于编译器允许以下内容:

  1. List a = new ArrayList();

  2. List <?> b = a;

  3. List <? extends Object> c = a; // with warning of course

    for (Object obj : b) {}
    // I don't agree with your statements above that &lt;?&gt; cannot be 
    
    // written in the for (:) loop as shown here
    for (Object obj : c) {}
    
两者都可以。所以我仍然不明白为什么将原始类型赋值给<? extends Object>时会出现未经检查的警告。

5
区别在于,raw 表示没有指定类型,而 <? extends Object> 是特定的有界类型定义。因此从没有类型某些类型这是一种未经检查的转换。 - Johannes Wachter
那么为什么 List <?> list2 = list; // 能够工作呢?这里没有警告。 它也是将某些类型分配给无类型(<? > 和 <? extends Object> 之间的唯一区别在于前者是无界的,而后者是有界的)。 - yapkm01
5个回答

2

这个问题,尤其是这个答案,详细说明了?? extends Object之间的区别。但我仍然没有找到任何解释为什么从List赋值到List<? extends Object>会得到一个警告。


1

如果我想得没错的话,那么编译器默认你是指这个。

List<?> list = new ArrayList();

问号表示你可以使用任何泛型类型。这就是为什么

List list = new ArrayList();
List <?> list2 = list

这是有效的,因为对于编译器来说它们是相同的东西。

然而,当你这样做时

List<?> list = new ArrayList();
List<? extends Object> list2 = list

你正在限制它的范围。因为你正在限制范围,所以你会得到一个警告。是的,我知道你不认为你在限制,但对于编译器来说是这样的。如果你非常确定自己知道在做什么,那就忽略它或者抑制它。


0
假设我们在list1中使用Runnable而不是Object。它可以编译通过,但会在运行时出现错误:
 List  list = new ArrayList ();
 list.add("a");
 List <? extends Runnable> list1 = list;
 for(Runnable o:list1){ //Runtime exception-> java.lang.ClassCastException
    o.run(); 
 }

这个案例展示了潜在的问题,这就是为什么要在这里发出警告。

但是你的IDE只检查语法List <? extends SomeType>,无论SomeType是一个Object还是其他类型。


0

我认为这是由于Java处理有界通配符的方式导致的,即List<? extends Object>不同于List,也不是它的子类。

最初,这个概念对我来说有些困惑,我发现Java编程语言中的泛型文档在理解这些特定类型的泛型方面非常有用。


0

我认为Shengyuanl Lu已经非常准确地解释了。我想补充一点,当你看到这样的事情时,只需记住以下两点:

  1. 你不能将“任何类型”的容器强制转换为“有界类型”的容器(无论前者是否绑定到Object类型)。
  2. 每当你这样做时,都会创建“堆污染”(请参阅Angelika Langer的Java泛型FAQ的描述)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接