为什么arraylist类实现List以及扩展AbstractList?
java.util.ArrayList
实现实现List
以及扩展AbstractList
。 但是在java文档中你可以看到AbstractList已经实现了List。 那么实现List以及扩展AbstractList不是多余的吗?
我的第二个问题
请看下面的代码:
String str = "1,2,3,4,5,6,7,8,9,10"; String[] stra = str.split(","); List a = Arrays.asList(stra);
Arrays类的Arrays.asList()
方法包含自己的ArrayList实现。 但是这个只扩展了AbstractList,但没有实现List。 但上面的代码编译。
但是当代码被修改为以下内容时
String str = "1,2,3,4,5,6,7,8,9,10"; String[] stra = str.split(","); java.util.ArrayList a = Arrays.asList(stra);
我收到一个错误: cannot convert form List to ArrayList
这背后的原因是什么?
编辑
Arrays.asList()
确实返回自己的ArrayList实现。 看看这个 。
对于你的第一个问题,看看为什么ArrayList有“实现列表”?
回答你的第二个问题
java.util.ArrayList a = Arrays.asList(stra);
正如您所提到的, Arrays.asList
返回自己的AbstractList 实现 ,不幸的是,此代码的创建者也将此类命名为ArrayList。 现在因为我们不能水平转换但只有垂直返回的数组列表不能转换为java.utli.ArrayList
而只能转换为java.util.AbstractList
或其超类型如java.util.List
,这就是你的第一个代码示例工作的原因。
那么实现List以及扩展AbstractList不是多余的吗?
是的,这是100%多余的。 但是,Java实现者在集合库的所有公共实现中非常一致地添加了接口:
-
LinkedList
和ArrayList
扩展AbstractList
,它实现List
,然后自己实现List
。 -
HashSet
和TreeSet
扩展AbstractSet
,实现Set
,然后自己实现Set
。 -
HashMap
和TreeMap
扩展AbstractMap
,它实现Map
,然后自己实现Map
。
我的理解是他们这样做是出于文档目的:作者想要表明ArrayList
主要是List
; ArrayList
扩展AbstractList
的事实是其实现的一个不太重要的细节。 其他公共collections类型也是如此。
请注意, Arrays.ArrayList
类不是公开可见的,因此其作者并不关心显式包含List
。
对于失败的转换,这应该不足为奇,因为内部类Arrays.ArrayList
和公共类ArrayList
彼此无关。
Arrays.asList返回一个List 。 因此,将它转换为ArrayList是不安全的,因为您不知道返回什么类型的List (取决于它从中创建列表的数组类型)。 你的第二个片段隐式地想要一个ArrayList 。 因此,当您的第一个代码段编译正常时它会失败,因为它需要一个List 。 你可以做-
ArrayList a = new ArrayList (Arrays.asList(stra));
第一个问题的答案是实施List是一份合同。 该契约可以由AbstractList和ArrayList定义。 ArrayList实现了List,以便在将来可能需要扩展而不是可能实现或不实现List的AbstractList时,发布将尊重List契约的事实。
对于第二个问题:Arrays.asList返回一个List。 可能会发生在当前实现中返回ArrayList。 在下一个版本中可以返回一个不同的列表LinkedList,例如,合同(由方法签名定义)仍将被尊重。
我相信,有一个原因。 这只是我的想法,我没有在JLS的任何地方找到它。
如果我是一名正在编写广泛使用的API的开发人员,为什么我会这样做呢?
绝对没有理由这样做,但考虑这种情况,我已经编写了List
接口并为List
接口提供了ArrayList
实现。
到目前为止,我还没有编写任何抽象类AbstractList
。
有一天需求来了,我被要求编写更多的List
接口实现,其中大多数实现了List
接口中abstract
方法的相似或相同的具体方法。
我将继续编写一个AbstractList
其中包含所有这些方法的必要实现。 但是现在我不希望我的一半类实现List
接口,其中一半扩展AbstractList
。
此外,我不能只从我之前写的类中删除’implements List`,可能是因为这不是正确的时间,或者我不希望其他代码与我的新版本打破。
注意这完全是我的意见。
1) ArrayList implements List
是多余的但仍然合法。 只有JCF(Java Collection Framework)设计师才能回答原因。 由于领导JCF设计师J.Bloch没有说明为什么它在“有效Java”中是这样的,似乎我们永远不会知道为什么。
2)Arrays.asList返回
public class Arrays { ... private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { ...
它不是java.util.ArrayList,也不能强制转换为它
我会简单而直接地回答我的问题。
实现List以及扩展AbstractList不是多余的吗?
是的,它是,但他们只是为了澄清代码,很容易看到该类实现了List接口。
Arrays类的Arrays.asList()方法包含自己的ArrayList实现。 但是这个只扩展了AbstractList,但没有实现List。
如您所见,这是多余的,如果AbstractList已经声明了该实现,则不需要重新声明List接口的实现。
我得到一个错误:无法将表单List转换为ArrayList这背后的原因是什么?
Arrays.asList()返回一个List,它可以是任何类型的List。 在该代码中实现的ArrayList与java.util.ArrayList的ArrayList不同,它们只是共享相同的名称,但它们不是相同的代码。
只是想补充问题2的答案
java.util.ArrayList a=Arrays.asList(stra);
编译器只知道Arrays.asList
的返回类型是List
,但不知道它的确切实现,可能不是java.util.ArrayList
。 所以你得到了这个编译时错误。
类型不匹配:无法从List转换为ArrayList
你可以像这样明确强迫上层
java.util.ArrayList a =(java.util.ArrayList )Arrays.asList(stra);
代码将成功编译,但会发生运行时exception,
java.lang.ClassCastException: java.util.Arrays $ ArrayList无法强制转换为java.util.ArrayList
这是因为java.util.Arrays$ArrayList
( Arrays.asList
返回的实现类型)不是java.util.ArrayList
的子类型。