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

发布于 2024-11-08 04:51:19 字数 970 浏览 0 评论 0原文

有人可以向我解释为什么下面的代码示例中标记为 //this line 给出编译错误(为什么?) 的行不起作用吗?

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 类型时,是不是意味着它的每个元素都是 B 的实例?如果是这样,那么如果我们可以将 B 的各个实例强制转换为 A,那么将其强制转换为 ArrayList 会出现什么问题?

谢谢。

Can someone please explain to me why the line marked //this line gives a compile error (why?) in the following code sample does not work?

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;
    }
}

Specifically, when we say that bList is of type ArrayList<B>, does it not mean that each element of it is an instance of B? If so, then what is the problem in casting it to ArrayList<A>, if we can cast individual instances of B to A?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冬天旳寂寞 2024-11-15 04:51:19

问题是这样的:

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

The problem is this:

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?

If you do the same thing with arrays, you get an ArrayStoreException in line 4 at runtime. For generic collections, it was decided to prevent that kind of thing at compile time.

赠意 2024-11-15 04:51:19

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

ArrayList aList 只能引用 A 类型的 ArrayList


来自 wiki

与数组不同,泛型类是
既不是协变也不是逆变。
例如,List
List
其他:

// a 是 String 的单元素列表
列表<字符串> a = new ArrayList();
a.add("foo");

// b 是一个对象列表
列表<对象> b = a; // 这是一个编译时错误

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

// a 是 String 的单元素列表
列表<字符串> a = new ArrayList();
a.add("foo");

// b 是一个包含任何内容的列表
列表 b = a;

// 检索第一个元素
对象 c = b.get(0);
// 这是合法的,因为我们可以保证
// 返回类型“?”是对象的子类型

// 添加一个 Integer 到 bbadd(new Integer (1)); 
// 这是一个编译时错误; 
// 我们不能保证 Integer 是
// 参数类型“?”的子类型

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

Because generic are strict. they aren't covarient

ArrayList<A> aList can only refer to an ArrayList of type A


From wiki

Unlike arrays, generic classes are
neither covariant nor contravariant.
For example, neither List<String> nor
List<Object> is a subtype of the
other:

// 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

However, generic type parameters can
contain wildcards (a shortcut for an
extra type parameter that is only used
once). Example: Given a requirement
for a method which operates on Lists,
of any object, then the only
operations that can be performed on
the object are those for which the
type relationships can be guaranteed
to be safe.

// 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 "?"

Wildcards can also be bound, e.g. "?
extends Foo
" or "? super Foo" for
upper and lower bounds, respectively.
This allows to refine permitted
performance. Example: given a List<?
extends Foo>
, then an element can be
retrieved and safely assigned to a Foo
type (covariance). Given a List<?
super Foo>
, then a Foo object can be
safely added as an element
(contravariance).

毁梦 2024-11-15 04:51:19

Animesh,

即使 B 类是 A 的子类型,ArrayList < B>不是 ArrayList < 的子类型A>.它与 B[] 位于同一行,不是 A[] 的子类型。这是两个独立的、不相关的类型。

Animesh,

Even though class B is subtype of A, ArrayList< B > is not a subtype of ArrayList < A >. Its on the same line as in B[] is not subtype of A[]. These are two independent unrelated types.

终难愈 2024-11-15 04:51:19

因为在 Java 中,CC 之间没有子类型关系,即使 AB 的超类型,反之亦然。

如果您对详细信息感兴趣,请在维基百科中查找协方差/逆变方差。

请注意,在 Java 中数组是协变的,这意味着如果 AB。这就是为什么有时会遇到数组奇怪的强制转换异常的原因。

Because there is no subtype relation in Java between C<A> and C<B>, even if A is a supertype of B or vice versa.

If your interested in the details lookup co- / contra-variance in Wikipedia.

Note, that in Java arrays are co-variant, which means A[] is a supertype of B[] if A is a supertype of B. That is the reason why you sometimes get strange cast exception with arrays.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文