为什么arraylist类实现List以及扩展AbstractList?

时间:2013-09-01 12:40:42

标签: java arrays arraylist

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<String> 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<String> a = Arrays.asList(stra);

我收到错误:cannot convert form List<String> to ArrayList<String>
这背后的原因是什么?
修改
Arrays.asList()确实返回自己的ArrayList实现。检查this

8 个答案:

答案 0 :(得分:26)

  

那么实现List以及扩展AbstractList不是多余的吗?

是的,它是100%多余的。但是,Java实现者在集合库的所有公共实现中非常一致地添加了接口:

  • LinkedList<E>ArrayList<E>扩展AbstractList<E>,实现List<E>,然后自行实施List<E>
  • HashSet<E>TreeSet<E>扩展AbstractSet<E>,实现Set<E>,然后自行实施Set<E>
  • HashMap<K,V>TreeMap<E>扩展AbstractMap<K,V>,实现Map<K,V>,然后自行实施Map<K,V>

我的理解是他们出于文档目的这样做:作者希望证明ArrayList<E>主要是List<E>; ArrayList<E>扩展AbstractList<E>的事实是其实施的一个不太重要的细节。其他公共收藏类型也是如此。

请注意,Arrays.ArrayList<E>类未公开显示,因此其作者无需明确包含List<T>

对于失败的转换,这应该不足为奇,因为内部类Arrays.ArrayList<E>和公共类ArrayList<E>彼此无关。

答案 1 :(得分:6)

关于第一个问题,请查看Why does ArrayList have "implements List"?


回答你的第二个问题

java.util.ArrayList<String> a = Arrays.asList(stra);

正如您所提到的,Arrays.asList返回其抽象列表的own implementation,不幸的是,此代码的创建者也将此类命名为ArrayList。现在因为我们不能水平投射,但只能垂直返回的数组列表不能投射到java.utli.ArrayList但只投射到java.util.AbstractList或其超级类型如java.util.List这就是你的第一个代码示例的原因的工作原理。

答案 2 :(得分:3)

Arrays.asList会返回列表。因此,将其转换为 ArrayList 并不安全,因为您不知道返回了什么类型的 List (取决于它从中创建列表的数组类型)。您的第二个代码段隐式地需要 ArrayList 。因此,当您的第一个代码段编译正常时,它会失败,因为它需要 List 。你可以做 -

ArrayList<String> a = new ArrayList<String>(Arrays.asList(stra));

答案 3 :(得分:2)

1)ArrayList implements List是多余的,但仍然合法。只有JCF(Java Collection Framework)设计师才能回答原因。由于领导JCF设计师J.Bloch没有说“为什么它在”有效Java“中这样,我们似乎永远不知道为什么。

2)Arrays.asList返回

public class Arrays {
   ...

    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
...

它不是java.util.ArrayList,也不能强制转换为它

答案 4 :(得分:2)

你的第一个问题的答案是实施List是一份合同。该合约可以由AbstractList和ArrayList定义。 ArrayList实现了List,以便在将来可能需要扩展而不是可能实现或不实现List的AbstractList时,发布将遵守List契约的事实。

对于第二个问题:Arrays.asList返回一个List。可能会发生在当前实现中返回ArrayList。在下一个版本中可以返回一个不同的列表LinkedList,例如,合同(由方法签名定义)仍然会得到尊重。

答案 5 :(得分:2)

我相信,有一个原因。这只是我的想法,我没有在JLS的任何地方找到它。

如果我是一名正在编写广泛使用的API的开发人员,我为什么要这样做?

绝对没有理由这样做,但请考虑这种情况,我编写了List接口并为ArrayList接口提供了List实现。

到目前为止,我还没有写过任何抽象类AbstractList

有一天会有一个要求出现,我被要求写几个List接口的更多实现,其中大部分都有abstract List方法的相似或相同的具体方法} interface。

我将继续编写AbstractList,并为所有这些方法编写必要的实现。但是现在我不希望我的一半类实现List接口,其中一半扩展AbstractList

另外,我不能只从我之前写的类中删除'implements List`,可能是因为这不是正确的时间,或者我不希望其他代码与我的新版本分开。

注意这完全是我的意见。

答案 6 :(得分:1)

我的答案会简单直接。

  

实现List以及扩展并不是多余的   AbstractList中?

是的,确实如此,但他们只是为了澄清代码,很容易看到该类实现了List接口。

  

Arrays类的Arrays.asList()方法包含它自己的方法   ArrayList的实现。但是这个只扩展了AbstractList   但是没有实现List。

正如您所看到的,这是多余的,如果AbstractList已经声明了该实现,则不需要重新声明List接口的实现。

  

我收到错误:无法将表单List转换为ArrayList   这背后的原因是什么?

Arrays.asList()返回一个List,它可以是任何类型的List。在该代码中实现的ArrayList与java.util.ArrayList的ArrayList不同,它们只是共享相同的名称,但它们不是相同的代码。

答案 7 :(得分:1)

只是想补充问题2的答案

java.util.ArrayList<String> a=Arrays.asList(stra);

编译器只知道Arrays.asList的返回类型是List,但不知道它的确切实现可能不是java.util.ArrayList。所以 你得到这个编译时错误。

  

类型不匹配:无法从List转换为ArrayList

你可以像这样明确强制施法,

java.util.ArrayList<String> a =(java.util.ArrayList<String>)Arrays.asList(stra);

代码将成功编译,但会发生运行时异常,

  

java.lang.ClassCastException: java.util.Arrays $ ArrayList 不能   强制转换为 java.util.ArrayList

这是因为java.util.Arrays$ArrayListArrays.asList返回的实现类型)不是java.util.ArrayList的子类型。