为什么将ArrayList的泛型转换为超类不起作用?

时间:2011-05-18 12:01:01

标签: java generics casting

有人可以向我解释为什么以下代码示例中标记为//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;
    }
}

具体来说,当我们说bList属于ArrayList<B>类型时,是否并不意味着它的每个元素都是B的实例?如果是,那么如果我们可以将ArrayList<A>的单个实例转换为B,那么将其转换为A会出现什么问题?

感谢。

4 个答案:

答案 0 :(得分:10)

问题在于:

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。对于泛型集合,决定在编译时阻止这种事情。

答案 1 :(得分:5)

因为通用是严格的。他们不是协变的

ArrayList<A> aList只能引用ArrayList类型的A


来自wiki

  

与数组不同,泛型类是   既不协变也不逆变。   例如,既不List<String>也不   List<Object>是该类型的子类型   其他:

// 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对象就可以   安全地添加为元素   (逆变)。

答案 2 :(得分:0)

的Animesh,

即使B类是A的子类型,ArrayList&lt; B>不是ArrayList的子类型&lt; A&gt;。它与B []在同一行上不是A []的子类型。这是两种独立的无关类型。

答案 3 :(得分:0)

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

如果您对维基百科中的详细信息查找共同/反向差异感兴趣。

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