【发布时间】:2011-09-09 18:58:17
【问题描述】:
我有一个关于将子类列表分配给超类列表的基本问题。
所以我有如下内容:
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
为什么最后一次分配失败?抱歉新手问题
【问题讨论】:
我有一个关于将子类列表分配给超类列表的基本问题。
所以我有如下内容:
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
为什么最后一次分配失败?抱歉新手问题
【问题讨论】:
为了解释这一点,让我用整数替换“B”,用数字替换“A”。这只是为了让它更容易解释。
Class Integer extends Number;
List <Integer> iList = new ArrayList<Integer>();
List <Number> nList = iList // will fail
这会失败的原因是因为 nList 可以接受任何数字——它可以接受整数,它可以接受双精度数,或者任何数字的子类。但是,对于 iList 来说,情况并非如此。您不能将 Double 添加到 iList,因为它只接受 Integer 及其子类。希望这有助于向您解释。
【讨论】:
当您声明类型 A 的项目列表时,只能从列表中添加或删除类型 A 的项目。如果您需要包含 A 的子类,请使用通用通配符 ? extends A 来表示。因此,您的代码应该是:
List <? extends A> aList = bList;
【讨论】:
List<B> 不是List<A>:
通过示例:假设您有class B1 extends A{} 和class B2 extends A{}
那么(如果你能做到的话:
List<B1> b1 = new AList<B1>();
List<A> a = b1;
List<B2> b2 = new AList<B2>();
根据假设,您应该能够做到 a.add(新 B2()) 但这是错误的。
如果您尝试相同的操作但使用arrays 而不是列表,它将编译并在运行时抛出异常。
我们说数组是协变的,而泛型是不变的。
要编译代码,你有技巧:
List<? extends A> a = b;
这表示a 是A 的一些子类型 的列表。_但你不知道是哪一个。因此你不能这样做a.put(X)
【讨论】:
List<B> 和 List<A> 是 invariant 类型。你需要的是covariant 类型。在这种情况下,它是List<? extends A>。
【讨论】:
因为泛型是严格类型安全的。
你可以拥有
List<? extends A> aList = bList;
它说aList 可以保存A 的任何类型的列表
【讨论】:
因为List<B> 没有扩展List<A>。例如,Integer 扩展了 Number,Long 也是如此。所以List<Number> 可以同时包含Integer 和Long。因此,如果您将List<Integer> 分配给List<Number>,您将能够将Long 添加到您的整数列表中。
你可以声明
List<? super B> superB;
这将允许将任何包含 B 及其超类的列表分配给 superB。
但这与您的情况不一样aList=bList。
或
List<? extends A> extendsA;
例子
List<? super Integer> superA;
superA = new ArrayList<Number>();
List<? extends Number> extendsNumber;
extendsNumber = new ArrayList<Integer>();
【讨论】:
乍一看你可能会这样认为
Class B extends A;
List <B> bList = new ArrayList<B>();
List <A> aList = bList;
应该可以,当您想象实际使用这些列表时,问题就很明显了:
A something = new A();
aList.add( something ); // Should work because aList is a list of A's
但是aList被分配给bList,所以应该和
bList.add( something ); // Here's the problem
bList.add() 采用B,但something 是A,而A 不是B!
这就是为什么泛型应该(并且是)严格类型安全的原因。
【讨论】: