【问题标题】:Why does casting an ArrayList 's generic to a superclass not work?为什么将 ArrayList 的泛型转换为超类不起作用?
【发布时间】:2011-05-18 12:01:01
【问题描述】:

有人可以向我解释一下为什么以下代码示例中标记为//this line gives a compile error (why?) 的行不起作用吗?

import java.util.ArrayList;

public class GenericCastCheck {

    class A{
    }

    class B extends A{
    }

    public static void main(String[] args) {

        A aObject = new A();
        B bObject = new B();

        //this line works fine
        aObject = bObject;
        //this line gives a compile (expected)
        bObject = aObject;

        ArrayList<A> aList = new ArrayList<A>();
        ArrayList<B> bList = new ArrayList<B>();

        //this line gives a compile error (why?)
        aList = bList;
        //this line gives a compile error (expected)
        bList = aList;
    }
}

具体来说,当我们说bListArrayList&lt;B&gt; 类型时,不是说它的每个元素都是B 的一个实例吗?如果是这样,那么将其转换为 ArrayList&lt;A&gt; 有什么问题,如果我们可以将 B 的单个实例转换为 A

谢谢。

【问题讨论】:

    标签: java generics casting


    【解决方案1】:

    问题是这样的:

    ArrayList<A> aList = new ArrayList<A>();
    ArrayList<B> bList = new ArrayList<B>();
    aList = bList; // if this were valid...
    aList.add(new A()); // ...what should happen here?
    B b = bList.get(0); // ...and here?
    

    如果你对数组做同样的事情,你会在运行时在第 4 行得到一个 ArrayStoreException。对于泛型集合,决定在编译时防止这种事情发生。

    【讨论】:

    • 非常感谢。我意识到我应该使用aList = new ArrayList&lt;A&gt;( bList); 而不是aList = bList,它也编译得很好。 :)
    【解决方案2】:

    因为泛型是严格的。它们不是协变的

    ArrayList&lt;A&gt;aList 只能引用A 类型的ArrayList


    来自wiki

    与数组不同,泛型类是 既不协变也不逆变。 例如,List&lt;String&gt;List&lt;Object&gt; 是 其他:

    // a is a single-element List of String
    List<String> a = new ArrayList<String>();
    a.add("foo");
    
    // b is a List of Object
    List<Object> b = a; // This is a compile-time error
    

    但是,泛型类型参数可以 包含通配符( 仅使用的额外类型参数 一次)。示例:给定一个要求 对于在列表上运行的方法, 任何对象,那么唯一的 可以执行的操作 对象是那些 可以保证类型关系 为了安全。

    // a is a single-element List of String
    List<String> a = new ArrayList<String>();
    a.add("foo");
    
    // b is a List of anything
    List<?> b = a;
    
    // retrieve the first element
    Object c = b.get(0);
    // This is legal, because we can guarantee
    // that the return type "?" is a subtype of Object
    
    // Add an Integer to b.
    b.add(new Integer (1)); 
    // This is a compile-time error; 
    // we cannot guarantee that Integer is
    // a subtype of the parameter type "?"
    

    通配符也可以绑定,例如“? extends Foo”或“? super Foo” 分别为上限和下限。 这允许细化允许 表现。例子:给定一个List<? extends Foo>,那么一个元素可以是 检索并安全分配给Foo 类型(协方差)。给定一个List<? super Foo>,那么一个Foo 对象可以是 安全地添加为元素 (逆变)。

    【讨论】:

      【解决方案3】:

      动漫,

      即使类 B 是 A 的子类型,ArrayList 也不是 ArrayList 的子类型。它与 B[] 在同一行不是 A[] 的子类型。这是两个独立的不相关类型。

      【讨论】:

        【解决方案4】:

        因为在Java 中C&lt;A&gt;C&lt;B&gt; 之间存在no 子类型关系,即使AB 的超类型,反之亦然。

        如果您对 Wikipedia 中的详细信息查找协方差感兴趣。

        注意,在 Java 中数组是协变的,这意味着如果 AB 的超类型,则 A[]B[] 的超类型。这就是为什么你有时会遇到奇怪的数组转换异常的原因。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-04
          • 2023-03-12
          • 1970-01-01
          • 2013-01-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多