Java 集合框架包含非常有用的接口和类,实现它们便可处理数据结构。可以说,这是最重要的 JDK 框架之一。List 接口广受欢迎。因为在编程中不需要各种各样的列表,List 接口是必不可少的。在本文中,我们将介绍此接口、Java List 方法和实现。

Java List 接口

列表最重要的一点是它是一个有序的集合。你也可以称之为序列。在 Java 中,列表是同构的,也就是说,列表的元素是相同的数据类型。Java List 接口继承自 Collection,继承了后者的所有操作。除此之外,在 List 中还可以进行以下操作:
  • 位置访问。每个元素都有一个索引,可以根据它们的位置在列表中进行操作。也就是说,你可以添加、排除和修改元素。
  • 搜索。你可以通过内容在列表中找到一个元素并返回它的索引。
  • 迭代。List 所具有的序列性质允许使用迭代方法 (listIterator)。
  • 视野范围。子列表方法在列表上执行任意范围的操作。

Java List 方法

上述操作在 Java List 接口的方法中公开。下面列出了其中的一些方法:
方法 说明
add(E element) 此方法将 element 元素添加到列表的末尾。
add(int index, element) 方法在列表中的特定索引处添加元素。如果传递了所需的参数,它会在列表末尾添加元素。
addAll(int index, Collection collection) 将给定集合中的所有元素添加到列表中。如果传递一个参数,它将给定集合的所有元素添加到列表的末尾。
size() 返回列表的大小(列表中元素的数量)。
get(int index) 返回指定索引处的元素。
set(int index, element) 用新元素替换给定索引处的元素,并返回被新元素替换的元素。
remove(int index) 从指定索引中移除元素。
remove(element) 移除列表中给定元素的第一个匹配项。
clear() 从列表中移除所有元素。
indexOf(element) 返回给定元素的第一个匹配项。如果元素不在列表中,则返回 -1
lastIndexOf(element) 返回给定元素的最后一个匹配项。如果元素不在列表中,则返回 -1
equals(element) 比较给定元素与列表元素的相等性。
hashCode() 返回给定列表的哈希值。
isEmpty() 检查列表是否为空。如果列表为空,则返回 true。
contains(element) 检查列表是否包含元素。如果列表包含元素,则返回 true。
containsAll(Collection collection) 检查列表是否包含所有元素的集合。
sort(Comparator comp) 根据给定的比较器对列表中的元素进行排序。
subList(int fromIndex, int toIndex) 返回此列表在指定的 fromIndex(含)到 toIndex(不含)之间部分的视图。

List 实现

因为 List 是一个接口,程序需要创建它的具体实现。你可以在 Java Collections API 的以下 List 实现中进行选择:
  • java.util.ArrayList
  • java.util.LinkedList
  • java.util.Vector
  • java.util.Stack
List 接口最常用的实现称为 ArrayList。虽然不太常见,但你仍然可以在实际任务中看到 LinkedList 的使用,不过,Vector 和 Stack 实际上已过时很久了,因此你很可能只会在具有古老遗留代码的项目中找到它们。

List 接口声明

你可以通过以下方式之一在 Java 程序中声明 List:

List<String> myList = new ArrayList();
List myList1 = new ArrayList();
List myList3 = new ArrayList<String>();
ArrayList arrayList = new ArrayList();
最好通过一个接口声明一个新的列表。类似地,你可以声明 List 的其他实现。 最短的方法:

Vector myVector = new Vector;
LinkedList linkedList = new LinkedList();
Stack stack = new Stack();
通过这种声明,这种列表的元素的数据类型在列表的初始化期间被确定,也就是当元素被添加到那里时被确定。

List myList = new ArrayList<String>();
Vector myVector = new Vector();
LinkedList linkedList = new LinkedList();
Stack stack = new Stack();
stack.add("Paul");
linkedList.add(1);
myVector.add(1.2f);
myList.add('a');
现在,只有字符串可以添加到堆栈中,整数可以添加到 linkedList,浮点数可以添加到 myVectormyList 是一个字符列表。

ArrayList 的工作方式?

如果你已经熟悉了常规数组,那么你对 ArrayList 也有点熟悉了。其实 ArrayList 是一个动态数组,内部是一个普通数组。该数组充当数据存储。ArrayList 只存储引用类型、任何对象,包括第三方类、字符串、输出流和其他集合。包装类用于在 ArrayList 中存储原始数据类型。 在创建列表时,我们可以立即设置其大小,但在大多数情况下不会这样做。默认情况下,ArrayList size = 10。 向 ArrayList 中添加新元素是什么样子的?首先,开始检查内部数组中是否有足够的空间,以及是否还有一个元素适合。如果有空间,新元素将被添加到列表的末尾,即最后一个元素后面的单元。它的索引将是 arraylist.size()。 如果我们刚刚创建了列表,它是空的,这意味着 arrayList.size() = 0。因此,新元素将被添加到索引为 0 的单元中。如果没有足够的空间,在 ArrayList 中创建一个新数组,大小为(旧数组的大小* 1.5)+ 1。根据同样的原理,插入是在列表中间进行的,但同时,插入元素之后的所有元素都向右移动。因此,如果数组中有 5 个元素,需要将一个元素插入到第 2 个单元(即第三个)中,那么 0 和 1 数组元素保留在原位,一个新元素出现在第 2 个单元中,它的前身进入第三个单元中,依此类推。

Java List 示例(Arraylist 实现)


import java.util.*;

public class ArrayListExample2 {
   public static void main(String[] args) {
       List<String> myFriendsList = new ArrayList();
       //we created list of some objects 
       System.out.println( "the size of myList before init = " + myFriendsList.size());
       myFriendsList.add("Alex");
       myFriendsList.add("Tanya");
       myFriendsList.add("Veloxy");
       myFriendsList.add("Alex");
       myFriendsList.add("Andrew");
       System.out.println(myFriendsList);
       System.out.println( "the size of myList after init = " + myFriendsList.size());

       myFriendsList.add("Ihor");
       System.out.println(myFriendsList);
       System.out.println("the size of my list = " +  myFriendsList.size());


       //here the program will print out the first appearance of "Alex" element
       System.out.println(myFriendsList.indexOf("Alex"));
       //program will print out the first appearance of "Alex" element starting from the element 0

       myFriendsList.remove(3);
       System.out.println(myFriendsList.get(3));
       System.out.println("after removing one of Alex's there is only one Alex: " + myFriendsList);
       System.out.println(myFriendsList.get(1));



       myFriendsList.clear();
       System.out.println("the size of the vector after clear method = " +  myFriendsList.size());

   }
}
以下是此程序的输出:
初始化之前 myList 的大小 = 0 [亚历克斯, 塔尼娅, 麦乐可斯, 亚历克斯, 安德鲁] 初始化之后 myList 的大小 = 5 [亚历克斯, 塔尼娅, 麦乐可斯, 亚历克斯, 安德鲁, 伊戈尔] 我的列表的大小 = 6 0 安德鲁 在移除其中一个亚历克斯后,只存在一个亚历克斯:[亚历克斯, 塔尼娅, 麦乐可斯, 安德鲁, 伊戈尔] 塔尼娅 清除方法后向量的大小 = 0 进程完成并出现退出代码 0

LinkedList 的工作方式?

在 LinkedList 中,元素实际上是同一链中的链接。每个元素除了存储的数据之外,都有一个指向上一个元素和下一个元素的链接。这些链接允许你从一个元素导航到另一个元素。迭代器支持双向遍历。实现在列表的开头、中间和结尾的获取、移除和插入的方法。允许你添加任何元素,包括 null。 LinkedList 实现了两个接口 — 不仅是 List,还有 Deque。这提供了从任何元素(甚至是 null)创建双向队列的能力。放在链表中的每个对象都是一个节点 (node)。每个节点包含一个元素,一个指向上一个节点和下一个节点的链接。事实上,链表由一系列节点组成,每个节点都被设计用来存储一个在创建时定义的类型的对象。

代码示例


import java.util.*;
public class LinkedListTest {

       public static void main(String args[]){

           List myLinkedList= new LinkedList<Integer>();
           myLinkedList.add(1);
           myLinkedList.add(2);
           myLinkedList.add(4);
           System.out.println("three added elements: " + myLinkedList);
           myLinkedList.add(5);
           myLinkedList.remove(1);
           System.out.println(myLinkedList);
           myLinkedList.size(); //3
           
           //add new element at the specified position:
           myLinkedList.add(2,7);
           System.out.println(myLinkedList);
                }
       }
输出如下所示:
三个添加的元素:[1, 2, 4] [1, 4, 5] [1, 4, 7, 5]

Vector 代码示例

Vector 也是一个动态数组实现,与 ArrayList 很相似,但是同步的,并且有一些集合框架没有包含的遗留方法。下面是这个类用法的一个简单例子。

import java.util.Vector;

public class VectorExample1 {

   public static void main(String[] args) {
       Vector vector = new Vector();
       System.out.println("the size of the empty vector = " +  vector.size());
       vector.add("Alex");
       vector.add("Tanya");
       vector.add("Andrew");
       System.out.println(vector);
       vector.add("Alex");
       vector.add("Ihor");
       System.out.println(vector);
       System.out.println("the size of the vector = " +  vector.size());
       System.out.println("the first element of the vector = " + vector.firstElement());

       //here the program will print out the first appearance of "Johnny" element
       System.out.println(vector.indexOf("Andrew"));
       //program will print out the first appearance of "Johnny" element starting from the element 1
       System.out.println(vector.indexOf("Alex", 1));
       System.out.println(vector);
       vector.clear();
       System.out.println("the size of the vector after clear method = " +  vector.size());

   }
}
输出是:
空向量的大小 = 0 [亚历克斯, 塔尼娅, 安德鲁] [亚历克斯, 塔尼娅, 安德鲁, 亚历克, 伊戈尔] 向量的大小 = 5 向量的第一个元素 = " + 亚历克斯 2 3 [亚历克斯, 塔尼娅, 安德鲁, 亚历克, 伊戈尔] 清除方法后向量的大小 = 0 进程完成并出现退出代码 0

Java Stack 类代码示例


import java.util.Stack;

public class StackTest {
   public static void main(String[] args) {
       Stack stack = new Stack();
       System.out.println(stack.isEmpty());
       stack.add("Paul");
       stack.add("Johnny");
       stack.add("Alex");
       System.out.println(stack.isEmpty());
       stack.push("Andrew");
       System.out.println(stack);
       stack.pop();
       System.out.println(stack);
   }
}
Stack不仅有 add()remove() 方法,还有 push 和 pop 方法,它们是这种数据结构的经典方法。堆栈遵循“先进后出”的规则,这是一种反队列。因此,pop 操作弹出最后放置在堆栈上的元素。 下面是我们示例的输出:
true false [保罗, 约翰尼, 亚历克斯, 安德鲁] [保罗, 约翰尼, 亚历克斯]