欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java集合(三)--List接口及其实现类

程序员文章站 2022-06-17 14:43:57
...

一、定义:

public interface List<E> extends Collection<E>

   通过观察List接口的定义发现其继承得是Collection接口,所以继承了Collection接口中的所有方法:

(1)Collection接口常用方法

1. public boolean add(E e);  //添加元素到集合
2. public boolean addAll(Collection<? extends E> c); //存放一个集合
3. public boolean contains(Object o);  //查找集合中的元素
4. public boolean isEmpty();  //判断一个集合是否为空
5. public boolean remove(Object 0);//删除一个集合中的元素
6. public int size();//返回集合的长度

 (2)List接口拓展了Collection接口中的方法

1. public E get(int index); //根据索引取得元素
2. public E set(int index,E element);//替换元素,index为要替换元素下标 element为要替换元素
3. public ListIterator<E> listIterator() List //List自己的迭代器

二、List的特点和实现类

1、特点:

      有序的,允许重复元素。顺序可以是自然排序或按对象加入到集合的顺序排序。因为List,所以它的对象可以被索引。ListIterator接口提供了迭代列表中元素的方法。抽象的List可以被随机的、通过数组、通过链接表或通过双向链接表进行访问。

2、list本身是一个接口,如果想要使用一个接口则可以使用该接口的实现类完成,重点实现类:ArrayList 、LinkedList 、Vector

(1)ArrayList : 底层数据结构是数组,允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。线程不安全

(2)LinkedList : 底层数据结构是链表。线程不安全,对顺序访问进行了优化,向List中间插入与删除快。随机访问则相对较慢。

(3)Vector: 底层数据结构是数组。线程安全。随机访问快,向List中间插入与删除慢。

三、ArrayList

1、简介:java.util Class ArrayList<E>

      ArrayList 是一个数组队列,相当于动态数组。线程不安全。

  • ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
  • ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
  • ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
  • ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

ArrayList包含了两个重要的对象:elementData 和 size。

(1) 、elementData 是"Object[]类型的数组",它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长。

(2) 、size 则是动态数组的实际大小。

2、ArrayList的三个构造函数

// 默认构造函数,ArrayList的默认容量大小是10。
ArrayList()

// capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。
ArrayList(int capacity)

// 创建一个包含collection的ArrayList
ArrayList(Collection<? extends E> collection)

3、关于ArrayList的常用方法,可以查看API

4、ArrayList的三种遍历方法

public class ArrayListTest {
	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(5);
		list.add(6);
		list.add(7);
		list.add(8);
		list.add(9);
		list.add(10);
		//通过迭代器遍历
		Iterator<Integer> iterator = list.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+" ");
		}
		System.out.println("\n--------------------------");
		//for循环遍历
		for (Integer integer : list) {
			System.out.print(integer+" ");
		}
		System.out.println("\n--------------------------");
		//随机访问,通过list.get(i)获得索引值去遍历。
		for(int i=0;i<list.size();i++) {
			System.out.print(list.get(i)+" ");
		}
	}
}

5、ArrayList是线程不安全的,可以看add()方法看出

public boolean add(E e) {
	ensureCapacityInternal(size + 1);  //确保容量是否充足
	elementData[size++] = e;           //将元素添加至数组
	return true;
}

从这一步,elementData[size++] = e;  我们知道add()添加元素的时候是分两步走的:

(1)elementData[size] = e;           

(2)size++;

     假设有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停(线程A仅仅完成了步骤1,Size没有自增),线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,此时 Size 仍然等于 0 ,所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。 

四、LinkedList

1、简介

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

  • LinkedList 实现 List 接口,能对它进行队列操作。
  • LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
  • LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
  • LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
  • LinkedList 是非同步的,即线程不安全的。

LinkedList的本质是双向链表。
(1)、 LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。 
(2) 、LinkedList包含两个重要的成员:header 和 size。
   header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,                previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。 
   size是双向链表中节点的个数。

2、LinkedList构造函数

// 默认构造函数
LinkedList()

// 创建一个LinkedList,保护Collection中的全部元素。
LinkedList(Collection<? extends E> collection)

先介绍一下AbstractSequentialList。毕竟,LinkedList是AbstractSequentialList的子类。

      AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。这些接口都是随机访问List的,LinkedList是双向链表;既然它继承于AbstractSequentialList,就相当于已经实现了上面这些接口。

3、LinkedList的原理

(1) LinkedList 实际上是通过双向链表去实现的。
        它包含一个非常重要的内部类:Entry。Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值上一个节点下一个节点
(2) 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
(3) LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
(4) LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
(5) 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

总结起来如下表:

      (头部操作)                        (尾部操作)
        抛出异常           特殊值           抛出异常            特殊值
插入    addFirst(e)     offerFirst(e)     addLast(e)        offerLast(e)
移除    removeFirst()   pollFirst()       removeLast()      pollLast()
检查    getFirst()      peekFirst()       getLast()         peekLast()

(6) 、LinkedList可以作为FIFO(先进先出)的队列,即用Linkedlist实现FIFO的队列时,下表的方法等价:

队列方法       等效方法
add(e)        addLast(e)
offer(e)      offerLast(e)
remove()      removeFirst()
poll()        pollFirst()
element()     getFirst()
peek()        peekFirst()

(7)、 LinkedList可以作为LIFO(后进先出)的栈,即用LinkedList作为LIFO的栈时,下表的方法等价:

栈方法        等效方法
push(e)      addFirst(e)
pop()        removeFirst()
peek()       peekFirst(

4、双线链表如何和索引值联系起来

      LinkedList实际上是通过双向链表去实现的。既然是双向链表,那么它的顺序访问会非常高效,而随机访问效率比较低。既然LinkedList是通过双向链表的,但是它也实现了List接口{也就是说,它实现了get(int location)、remove(int location)等“根据索引值来获取、删除节点的函数”}。LinkedList是如何实现List的这些接口的,如何将“双向链表和索引值联系起来的”?实际原理非常简单,它就是通过一个计数索引值来实现的。例如,当我们调用get(int location)时,首先会比较“location”和“双向链表长度的1/2”;若前者大,则从链表头开始往后查找,直到location位置;否则,从链表末尾开始先前查找,直到location位置。

5、LinkedList遍历方式:LinkedList支持多种遍历方式。不要采用随机访问的方式去遍历LinkedList(低效),而采用逐个遍历的方式。

举例三种:

package ListTest;

import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListTest {
	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(5);
		list.add(6);
		list.add(7);
		list.add(8);
		list.add(9);
		list.add(10);
		//通过迭代器遍历
		Iterator<Integer> iterator = list.iterator();
		while(iterator.hasNext()) {
			System.out.print(iterator.next()+" ");
		}
		System.out.println("\n--------------------------");
		//for循环遍历
		for (Integer integer : list) {
			System.out.print(integer+" ");
		}
		System.out.println("\n--------------------------");
		//随机访问,通过list.get(i)获得索引值去遍历,不建议
		for(int i=0;i<list.size();i++) {
			System.out.print(list.get(i)+" ");
		}
		
	}
	
}

五、Vector

1、简介

Vector 是矢量队列,底层是数组。它是JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。

  • Vector 继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能
  • Vector 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
  • Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。
  • Vector中的操作是线程安全的。因为Vector的方法前加了synchronized 关键字,所以效率不高。

2、构造函数:Vector共有4个构造函数

// 默认构造函数
Vector()

// capacity是Vector的默认容量大小。当由于增加数据导致容量增加时,每次容量会增加一倍。
Vector(int capacity)

// capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。
Vector(int capacity, int capacityIncrement)

// 创建一个包含collection的Vector
Vector(Collection<? extends E> collection)

3、Vector原理

(1)、 Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10
(2)、 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。
(3)、 Vector的克隆函数,即是将全部元素克隆到一个数组中。

4、遍历方式

Vector支持4种遍历方式。建议使用下面的第二种去遍历Vector,因为效率问题。

(1) 第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}

(2) 第二种,随机访问,通过索引值去遍历。
由于Vector实现了RandomAccess接口,它支持通过索引值去随机访问元素。

Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}

(03) 第三种,另一种for循环。如下:

Integer value = null;
for (Integer integ:vec) {
    value = integ;
}

(04) 第四种,Enumeration遍历。如下: 

Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
    value = (Integer)enu.nextElement();
}

借鉴博客:https://www.cnblogs.com/efforts-will-be-lucky/p/7052672.html

                 https://www.cnblogs.com/skywang12345/tag/%E9%9B%86%E5%90%88/