【问题标题】:Why does arraylist class implement List as well as extend AbstractList?为什么arraylist 类既要实现List 又要扩展AbstractList?
【发布时间】:2013-09-04 16:42:21
【问题描述】:

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&lt;String&gt; to ArrayList&lt;String&gt;
这背后的原因是什么?
EDIT
Arrays.asList() 确实返回了它自己的 ArrayList 实现。签出this

【问题讨论】:

  • 第一个问题的答案是肯定的,但是java就是这样
  • Arrays#asList 返回ArrayList
  • 不能将一个类分配给另一个实现相同接口的类,但您可以将它们分配给该接口。
  • @MarounMaroun :请参阅编辑。
  • @tommycake50 - 这个答案不正确。事实上,明确实施List 是有充分理由的。请参阅@Pshemo 的回答。

标签: java arrays arraylist


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    • LinkedList&lt;E&gt;ArrayList&lt;E&gt; 扩展实现 List&lt;E&gt;AbstractList&lt;E&gt;,然后自己实现 List&lt;E&gt;
    • HashSet&lt;E&gt;TreeSet&lt;E&gt; 扩展实现 AbstractSet&lt;E&gt;Set&lt;E&gt;,然后自己实现 Set&lt;E&gt;
    • HashMap&lt;K,V&gt;TreeMap&lt;E&gt; 扩展实现 AbstractMap&lt;K,V&gt;Map&lt;K,V&gt;,然后自己实现 Map&lt;K,V&gt;

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

    请注意,Arrays.ArrayList&lt;E&gt; 类不公开可见,因此其作者并不关心明确包含 List&lt;T&gt;

    就失败的转换而言,这应该不足为奇,因为内部类Arrays.ArrayList&lt;E&gt; 和公共类ArrayList&lt;E&gt; 彼此无关。

    【讨论】:

    • 在 Java 中可以肯定地说存在三种主要类型的列表。 1.列表 2.设置 3.地图
    【解决方案3】:

    1) ArrayList implements List 是多余的,但仍然合法。只有 JCF(Java 集合框架)设计者才能回答为什么。由于首席 JCF 设计师 J.Bloch 在“Effective Java”中没有说明为什么会这样,看来我们永远不会知道为什么。

    2) Arrays.asList 返回

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

    它不是 java.util.ArrayList 并且不能转换为它

    【讨论】:

      【解决方案4】:

      第一个问题请查看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,这就是您的第一个代码示例有效的原因。

      【讨论】:

        【解决方案5】:

        第一个问题的答案是实现 List 是一个合同。该合约可以由 AbstractList 和 ArrayList 定义。 ArrayList 实现 List 是为了在将来可能需要扩展而不是从可能实现也可能不实现 List 的 AbstractList 时遵守 List 契约的事实。

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

        【讨论】:

          【解决方案6】:

          我相信,这是有原因的。这只是我的想法,我在 JLS 的任何地方都找不到。

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

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

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

          有一天,一个需求来了,我被要求编写更多List 接口的实现,其中大多数在List 接口中对abstract 方法具有相似或相同的具体方法。

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

          另外,我不能只是从我之前编写的类中删除“实现列表”,可能是因为现在不是正确的时间,或者我不希望其他人的代码在我的新版本中中断。

          注意这只是我的意见。

          【讨论】:

            【解决方案7】:

            我的回答会简单直接。

            实现 List 和扩展不是多余的吗 抽象列表?

            是的,但他们这样做只是为了澄清代码,以便容易看到该类实现了 List 接口。

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

            如您所见,这是多余的,如果 AbstractList 已经声明了 List 接口的实现,则无需重新声明该实现。

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

            Arrays.asList() 返回一个列表,它可以是任何类型的列表。该代码中实现的ArrayList与java.util.ArrayList的ArrayList不同,只是同名而已,但代码不同。

            【讨论】:

              【解决方案8】:

              只是想补充问题 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 的子类型。

              【讨论】:

                猜你喜欢
                • 2013-08-26
                • 2010-10-21
                • 2019-07-11
                • 2013-05-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-08-02
                相关资源
                最近更新 更多