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

一、定义:

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/

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值