【问题标题】:When is it correct to use ArrayList or LinkedList instead of List when declaring variables/parameters? [duplicate]声明变量/参数时,什么时候使用 ArrayList 或 LinkedList 而不是 List 是正确的? [复制]
【发布时间】:2013-09-30 06:04:43
【问题描述】:

假设你有一个类似的类:

public class foo {
    private List<String> fooThings;

    public void doSomething(List<String> things) {
        // Do a bunch of things here
        // Possibly setting fooThings at some point as well
    }
}

声明是否适合指定具体类,例如ArrayList 而不是 List 接口?如果有,什么时候?

Edit> 这个问题与何时使用 LinkedList 以及何时使用 ArrayList 无关。这是一个单独的问题,在其他地方得到了回答。问题是什么时候声明应该是接口(列​​表)以清晰起见,什么时候应该指定一个实现,例如ArrayList 因为考虑到方法将要做什么或如何利用实例变量,这很重要。

【问题讨论】:

  • 当您想使用仅在该实现中可用的方法时(类似于docs.oracle.com/javase/7/docs/api/java/util/…)。
  • 查看右侧所有相关答案。
  • @Sotirios Delimanolis - 所有这些相关的答案都在问一个完全不同的问题?
  • @Nambari 考虑到当前的答案,您可能想再写一个...
  • @Nambari 我知道那种感觉...

标签: java


【解决方案1】:

通常您应该只使用接口List 来声明您的结构。但是,在极少数情况下,您需要使用仅适用于 List 的特定实现的特定方法,例如 LinkedListArrayList,那么您应该显式声明您的列表类型。但是,这限制了灵活性,应谨慎使用。

【讨论】:

    【解决方案2】:

    这不是ArrayList/LinkedList 的示例,但我认为返回List 的方法可以这样声明:

    public ImmutableList doSomething();
    

    ImmutableList 是 Guava 的 ImmutableList。这种声明清楚地表明返回的列表不打算被修改,因此它是由代码而不是 cmets 传达的(或仅在运行时尝试修改列表时出现异常)。

    【讨论】:

      【解决方案3】:

      使用抽象类型作为方法参数或字段声明是一种很好的做法。

      这使您的代码能够以您尚未想象的方式工作。

      因为我们在 Collection 框架中,所以我写了一些我在编码时使用的建议。

      如果我不需要知道我使用Iterable 接口的包的尺寸。这允许我使用foreach,并且我可以稍后传递不是来自 java 集合框架的各种类型。

      如果我需要包的大小,我会使用收集界面。

      如果我需要从包中挑选物品,我使用列表界面。

      当我需要对独特的项目进行操作时,我使用设置界面。

      通常我从可迭代开始,稍后我将其更改为其他类型,但这些只是少数例外而不是规则。

      【讨论】:

        【解决方案4】:

        简单的答案是当您想为用户定义他们可以期望的性能时

        基本上,如果您正在使用的只是一个List,并且它是什么样的列表并不重要,假设您只是打算遍历它然后将其声明为List

        但是,如果您想对列表执行特定操作,例如插入条目或大量获取第 n 个条目,那么让每个人都知道它是什么类型的列表以及性能预期是有意义的。

        【讨论】:

        • 恕我直言,您不应该仅仅因为它具有特定的使用模式就限制函数使用List 的特定实现。这就是 Javadoc 的用途,调用者可能已经准备好承受这种性能损失。
        • 如果您只是打算遍历,请将其声明为 Iterable 而不是列表。然后可以使用List、Set、Collection等类型。我非常不同意你认为类型与性能有关的观点。
        • @Alnitak - 好点 - 但 OP 询问 什么时候正确...。从来都不是很长的时间。
        • @Vash - 正是我的观点。如果只是迭代,那么谁在乎!正是在性能 需要暴露的时候,然后才应该暴露底层结构。 ArrayListLinkedList 之间的唯一区别(除了一些琐碎的部分)是性能。
        【解决方案5】:

        您可能希望确保列表接口未授予的列表的某些属性。在下面的示例中,您可能会传入一个不可序列化的列表,从而在类被序列化时导致运行时错误。 :

        public class foo implements Serializable{
        
        private List<String> fooThings;
        
        public void setFooThings(List<String> things) {
           fooThings = things;
        }
        

        }

        ArrayList 实现了可序列化。还有其他方法可以通过通用方法确保列表可序列化,例如

        public <T extends List & Serializable> setFooThings(T things) 
        

        【讨论】:

          【解决方案6】:

          您总是希望将变量声明为:

          private List<String> fooThings;
          

          这允许我们在实际使用 fooThings 时使用任何类型的列表、LinkedList、ArrayList 等。

          您可能会在程序的某些部分使用 LinkedList,然后在另一部分切换到 ArrayList,因为它更适合。我们希望在开发过程中为自己提供最大的灵活性。

          我们也可能遇到通过来自另一个类的参数初始化 fooThings 的情况。我们不想将其声明为特定类型的列表,因为这样我们将方法的调用者限制为使用这种特定类型的列表,或者在使用我们的方法之前将其列表类型转换为正确的类型,这会导致不必要的工作。

          【讨论】:

          • 这是否曾经受到性能问题的影响,类似于 OldCurmudgeon 的回答?例如,方法 willAddFiftyGazillionNewObjectsToYourCollectionOneAtATimeMethod(List fooThings)?
          • 注意:这似乎是一种非常糟糕的方法,只是试图了解性能问题是否是将要求限制为特定实现与接口的正当理由。
          【解决方案7】:

          写接口而不是实现总是好的。这将为处理实现传递接口的不同具体类型提供灵活性..

          您的示例代码是另一个抽象级别

          public class foo {
              private Collection<String> fooThings;
          
              public void doSomething(Collection<String> things) {
                  // Do a bunch of things here
                  // Possibly setting fooThings at some point as well
              }
          }
          

          优势 - 这将允许您处理不同的具体类型的输入。

          缺点 - 它将限制想要使用具体类型的任何特定功能。例如。您可能无法使用特定于 LinkedList 的 getFirst()。

          代码到接口 - 灵活/松散耦合的代码。 实现代码 - 用于特殊操作。

          【讨论】:

            猜你喜欢
            • 2013-01-08
            • 2020-12-26
            • 2021-12-16
            • 2014-11-12
            • 2014-07-28
            • 2012-04-08
            • 1970-01-01
            • 1970-01-01
            • 2010-09-15
            相关资源
            最近更新 更多