【问题标题】:List Interface (adding linkedlist to a list of lists)列表接口(将链接列表添加到列表列表中)
【发布时间】:2023-03-20 21:05:01
【问题描述】:

我刚刚发现了这个有效的代码

List<List<Integer>> parentList = new ArrayList<>();
LinkedList<Integer> curList = new LinkedList<>();
parentList.add(curList);

我想我有点被甩了,因为我没想到你可以将 LinkedList 添加到声明为 List 的东西中。我以为你必须做类似的事情

List<Integer>curList = new LinkedList<>();
parentList.add(curList);

我认为将 LinkedList 或 ArrayList 声明/初始化为 List 的全部意义在于,即使它们是作为 LinkedLists 和 ArrayLists 实现的,您也可以将它们添加到 List 中。

edit:或者我对我们将其作为抽象层执行这一事实感到困惑 - 我们将其声明为 List 以便即使它由 arraylists 和 linkedlists 组成,我们仍然可以使用相同的 List 接口函数他们都是。我们可以将链表添加到列表列表中,因为链表只是实现了 List 接口

【问题讨论】:

  • 您的“编辑”评论是正确的。您使用接口正是因为您希望允许使用该接口的任何实现。您不在乎用户是否给您ArrayListLinkedList,您只需要List。有一天,您可能想要一个Database,而您不在乎它是MySQL 还是Postgresql,只要它实现了所有Database 方法即可。通过这种方式,您可以编写不太关心细节的代码。将代码放在最边缘处理它,内部可以更抽象地操作。

标签: java list arraylist linked-list


【解决方案1】:

tl;博士

这个:

LinkedList < Integer > curList = new LinkedList<>() ;  // <-- Declared as `LinkedList`.
parentList.add( curList ) ;

……还有这个:

List < Integer > curList = new LinkedList<>() ;        // <-- Declared as `List`.
parentList.add( curList ) ;

…具有相同的效果。

在这两种情况下,parentList 都期望收到一个包含Integer 对象的ListLinkedList 同时是 LinkedList List。所以通过定义为List 或定义为LinkedListcurList 没有区别。在这两种情况下,parentList.add 方法都会收到 List

LinkedList 对象分配给List 变量不会改变对象的性质。

List 表示任何类型的 List 实现:ArrayListLinkedList 等等

您的第一个集合 parentList 是一个列表列表。

  • 该列表中的每个元素本身就是另一个列表。声明 List&lt; List &lt; Integer &gt; &gt; parentList 告诉我们,我们有一个 Integer 对象列表的列表。
  • 外部列表和内部列表都可以是任何类型的List,不一定是ArrayListLinkedList

您的第二个集合curList 只是Integer 对象的列表。

  • 我们从它的声明中知道这一点,LinkedList &lt; Integer &gt; curList
  • 在此声明中,我们说列表绝对是LinkedList,而不是任何其他类型的List

这是一个完整的例子。

首先我们创建一个List 对象,其中包含Integer 对象的列表。这个外部列表是空的。

然后我们添加三个单位奇数(3、5、9)的列表。这个不可修改的列表是由List.of 方法生成的。用于List返回的对象的List的具体实现在未承诺的情况下,可能因情况和Java版本而异。我们所知道的是,我们正在一些实现List,其中包含Integer 对象。

然后我们创建一个LinkedList 持有Integer 对象。添加几个两位数后,我们将列表添加到外部列表中。

以下是这段代码中似乎让您感到困惑的关键点:

  • 我们可以将这个curList 变量声明为更通用的List &lt; Integer &gt; curList,而不是更具体的LinkedList &lt; Integer &gt; curList。用于curListList 的类型无关紧要。外部列表parentList 表示它不关心将哪个List 实现添加为元素,只关心添加的元素是someList,它包含Integer 对象。
  • 我们可以决定如果外部列表是LinkedList 而不是ArrayList,它会更好地服务。如果我们这样决定,我们可以简单地将List&lt; List &lt; Integer &gt; &gt; parentList = new ArrayList&lt;&gt;(); 更改为List&lt; List &lt; Integer &gt; &gt; parentList = new LinkedList&lt;&gt;();——其他代码都不会中断。我们可以将new ArrayList 切换为new LinkedList,而无需更改任何其他代码。这就是polymorphismOOP 中的好处。

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {

        List< List < Integer > > parentList = new ArrayList<>();
        parentList.add( List.of( 3 , 5 , 9 ) ) ;  // `List.of` returns *some* kind of (unmodifiable ) `List`; we do not know the concrete class nor do we care. 
        
        LinkedList < Integer > curList = new LinkedList<>();
        curList.add( 21 ) ;
        curList.add( 42 ) ;
        
        parentList.add(curList);
        System.out.println( parentList ) ;

    }
}

看到这个code run live on IdeOne.com

[[3, 5, 9], [21, 42]]

在该输出中,我们看到一个集合,一个包含两个元素的List。每个元素本身就是一个List,一个Integer 元素的列表。外部列表的第一个元素包含对三个Integer 对象列表的引用,而外部列表的第二个元素包含对两个Integer 对象列表的引用。

你说:

我想我有点被甩了,因为我没想到你可以将 LinkedList 添加到声明为 List 的东西中。

某物 (parentList) 被声明为列表列表。您传递的LinkedListList,所以它适合,它是一个匹配类型。任何LinkedList 也是List

如果您希望外部列表 (parentList) 仅包含 ArrayList 对象而不是任何类型的 List,您可以将其声明为:

List< ArrayList < Integer > > parentList = new ArrayList<>();

使用这样的声明,将new LinkedList&lt;&gt;() 传递给它的add 方法会导致编译器错误。方钉,圆孔。

但是,如果您的代码稍后需要 ArrayList 类独有的方法,而这些方法未在更通用的 List 接口中定义,则您只会进行声明。一般来说,你应该使用最通用的接口或满足你需要的超类,而不是更具体的具体类或子接口。如果List 有你以后的代码需要的方法,那么声明List&lt; List &lt; Integer &gt; &gt; parentList。这为您提供了灵活性。

你说:

我以为你必须做类似的事情

List&lt;Integer&gt;curList = new LinkedList&lt;&gt;();

parentList.add(curList);

当您将 LinkedList 对象分配给 List 变量时,您不会更改任何内容LinkedList 对象同时是 ListedList List

当您将curList 传递给parentList.add 方法时,该方法看到的只是List。将curList 声明为ListLinkedListadd 方法无关。编译器检查传递给 add 的任何内容是否是 (a) someList 实现,any List 实现,以及 (b) 持有 @ 987654420@ 个对象。

【讨论】:

    【解决方案2】:

    LinkedList 扩展 AbstractSequentialList 进而扩展 AbstractListArrayList 扩展 AbstractList。 所以LinkedListArrayList 都扩展了同一个子类。 List 接口上的 add 方法对添加类似类型的元素有限制。因此LinkedListArrayList 被认为是相似的,因此允许添加。

    同样,在逻辑上添加 LinkedList 并不会改变其中元素的行为,因为即使在添加到列表之后也会保持顺序。

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多