赞
踩
List接口的具体实现类:ArrayList、LinkedList、Vector
LinkedList的使用细节:
1.LinkedList中可以添加任意元素,包括null
2.LinkedList中的元素可以重复
3.LinkedList底层通过双向链表来存取数据
4.LInkedList中的方法没有使用synchronized修饰,因此只能单线程
LinkedList底层结构:
1.LinkedList底层维护了双向链表
2.LinkedList中维护了两个属性first、last,分别指向链表的首、尾节点
3.LinkedList每一个节点(Node)维护了三个属性prev、next、item
prev指向前一个节点,next指向后一个节点,item存储数据
因此,LinkedList通过双向链表完成数据的增删改查,而不是数组,相对效率更高。
- // 模拟双向链表
- Node jack = new Node("jack");
- Node tom = new Node("tom");
- Node kxg = new Node("kxg");
- // 连接三个节点,形成双向链表
- // Jack -> tom -> kxg
- jack.next = tom;
- tom.next = kxg;
- // kxg -> tom -> jack
- kxg.pre = tom;
- tom.pre = jack;
- // 双向链表的头、尾节点
- Node first = jack;
- Node last = kxg;
- // 从头到尾遍历双向链表
- while(true) {
- if (first == null) {
- break;
- }
- System.out.println(first);
- first = first.next;
- }
- // 从尾到头遍历双向链表
- while (true) {
- if (last == null) {
- break;
- }
- System.out.println(last);
- last = last.pre;
- }
- // 双向链表的添加与删除
- // 在tom与kxg中插入Smith
- Node smith = new Node("Smith");
- // 改变链表中的指向
- tom.next = smith;
- smith.next = kxg;
- kxg.pre = smith;
- smith.pre = tom;
-
- // 定义节点类:每一个Node类的实例对象都对应链表的一个节点
- class Node {
- private Object item; // 存储节点数据
- public Node prev; // 指向前一个节点
- public Node next; // 指向下一个节点
-
- // 构造器
- public Node(Object item) {
- this.item = item;
- }
- }
LinkedList的增删改查操作:
- LinkedList linkedList = new LinkedList();
- // 向链表中追加
- linkedList.add(12);
- linkedList.add("99");
- linkedList.add(25);
- linkedList.add("kxg");
- // 向链表中删除
- // remove():默认删除链表中的第一个节点
- // remove(int index):链表中的指定节点
- // remove(Object o):比较对象,做出删除
- linkedList.remove();
- // 修改链表
- linkedList.set(1, 100);
- // 得到链表中的某个元素
- Object obj = linkedList.get(0);
LinkedList的源码分析:
1.首先调用无参构造器,创建空链表。此时,first=null、last=null、size=0
public LinkedList() {};
2.向链表中添加首个元素,调用add方法。此时,first=last=该节点、size=1
- public boolean add(E e) {
- linkLast(e);
- return true;
- }
- // 进入linkLast()方法完成添加操作
- void linkLast(E e) {
- // 保存之前链表的尾节点
- final Node<E> l = last;
- // 创建新节点,prev=null;item=e;next=null
- final Node<E> newNode = new Node<>(l, e, null);
- // 改变链表中的last指向
- last = newNode;
- // 将新节点加入链表中
- if (l == null)
- // 首次添加链表为空时,first指向新节点
- first = newNode;
- else
- l.next = newNode;
- // 链表长度+1,修改次数+1
- size++;
- modCount++;
- }
3.向链表中再次追加元素,调用add方法,改变链表指向
- void linkLast(E e) {
- final Node<E> l = last;
- // 创建节点,pre=之前链表的last,item=e,next=null
- final Node<E> newNode = new Node<>(l, e, null);
- // 改变链表中的last指向
- last = newNode;
- // 将新节点加入链表中
- if (l == null)
- first = newNode;
- else
- // 链表不为空时,将新节点加入到链表的最后
- l.next = newNode;
- size++;
- modCount++;
- }
4.删除链表中的元素,调用remove方法
- public E remove() {
- return removeFirst();
- }
- public E removeFirst() {
- final Node<E> f = first;
- // 判断链表是否为空
- if (f == null)
- // 如果链表为空,抛出异常,方法结束
- // 链表不为空,调用unlinkFirst方法
- return unlinkFirst(f);
- }
- // 进入unlinkFirst方法
- private E unlinkFirst(Node<E> f) {
- // assert f == first && f != null;
- // 记录第一个节点中保存的数据和它指向的next节点
- final E element = f.item;
- final Node<E> next = f.next;
- // 将第一个节点的item、next都置为null
- f.item = null;
- f.next = null; // help GC
- // 将链表的first指向第一个节点指向的next
- first = next;
- if (next == null)
- // 链表仅仅只有一个元素,将first和last置为空
- last = null;
- else
- // 将新的第一个节点的prev置为null,断开与原来第一个的连接
- next.prev = null;
- // 长度-1
- size--;
- modCount++;
- return element;
- }
List的实现类:Vector
Vector类的使用细节:
1.Vector使用对象数组进行数据的存取。protected object[] elementData
2.Vector中的方法通过synchronized修饰,实现了线程同步(线程安全)
Vector的源码分析:
调用无参构造器:
- Vector vector1 = new Vector();
- for(int i = 0; i < 10; i++) {
- vector1.add(i);
- }
- vector1.add("kxg");
1.调用构造器
- public Vector() {
- this(10);
- }
2.Vector底层默认调用含参构造器,创建size=10的集合
- public Vector(int initialCapacity) {
- this(initialCapacity, 0);
- }
3.将元素加入集合中,判断是否需要扩容
- public synchronized boolean add(E e) {
- modCount++;
- ensureCapacityHelper(elementCount + 1);
- // 将元素加入集合中
- elementData[elementCount++] = e;
- return true;
- }
- private void ensureCapacityHelper(int minCapacity) {
- // overflow-conscious code
- // 根据minCapacity与elementData.length的大小,判断集合是否需要进行扩容
- if (minCapacity - elementData.length > 0)
- grow(minCapacity);
- }
4.对数组进行扩容
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- // capacityIncrement在双参构造器中,可以指定扩容的大小,默认为0
- // capacityIncrement=0,所以newCapacity=oldCapacity+oldCapacity,扩容两倍
- int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- // 需要存储的数据过多
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- // 将数组进行复制存储
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
调用含参构造器(一个参数):
- Vector vector2 = new Vector(8);
- for (int i = 0; i < 8; i++) {
- vector2.add("hello" + i);
- }
- vector2.add("kxg");
1.调用含参构造器,创建指定大小的数组,默认其扩容长度为0
- public Vector(int initialCapacity) {
- this(initialCapacity, 0);
- }
2.调用双参构造器
- public Vector(int initialCapacity, int capacityIncrement) {
- super();
- // 传入的参数<0,抛出异常
- if (initialCapacity < 0)
- throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
- // 创建指定大小的集合数组
- this.elementData = new Object[initialCapacity];
- // 默认扩容大小为0
- this.capacityIncrement = capacityIncrement;
- }
3.后面与无参构造器操作相同
调用含参构造器(两个参数):
- Vector vector3 = new Vector(4, 4);
- for (int i = 0; i < 4; i++) {
- vector3.add("kxg");
- }
- vector3.add("kxg");
1.调用含参构造器,传入初始大小、扩容大小
- public Vector(int initialCapacity, int capacityIncrement) {
- super();
- if (initialCapacity < 0)
- throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
- this.elementData = new Object[initialCapacity];
- this.capacityIncrement = capacityIncrement;
- }
2.按照指定大小进行扩容
Vector的扩容机制:
调用无参构造器,默认初始大小为8,之后按照两倍进行扩容
调用一个参数的构造器,默认初始大小为指定长度,之后按照两倍进行扩容
调用两个参数的构造器,默认初始大小为指定长度,之后按照指定大小进行扩容
ArrayList、LinkedList、Vector之间的区别与联系:
ArrayList:可变数组elementData[]
增加删除效率低,必须通过数组扩容进行处理
修改查询效率高
LinkedList:双向链表
增加删除效率高,仅仅改变链表中的指向
修改查询效率低
Vector:可变数组object[]
其中ArrayList、LinkedList都是线程不安全的,效率高;
Vector线程安全,效率低。
因此,存储数据时,多线程情况下选择Vector;单线程时,若对数据添加删除操作更多,选择LinkedList;若对数据修改查询操作更多,选择ArrayList
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。