浅谈ArrayList和LinkedList

ArrayList

源码分析

前言:刚开始学习java基础时,我们一般采用数组来存放数据,随着数组的使用,渐渐发现,数组只能存放一种数据类型并且数组长度是定长的。实际开发过程中,我们可能想让对象,基本数据类型都存放为一个容器中,这时候,集合就出现了

集合的继承树结构

ArrayList:它是实现List接口的子实现类,集合好比存放数据的容器,既然存放数据,简单的它会具有增,删,改,查,遍历等操作,此处我以jdk8分析底层源码走进ArrayList

@Test
	public void test() {  // 简单添加测试
		List list = new ArrayList();
		list.add(1);
		list.add("hello");
		list.add(new User("lisa", 20));
		System.out.println(list);
	}

–>开始走进源码

  1. List list = new ArrayList(); // 创建集合对象
    在这里插入图片描述
  2. add()源码
    在这里插入图片描述
  3. 扩容机制
    在这里插入图片描述

综合分析:ArrayList底层采用的是动态数组,具有扩容机制(注:jdk7类似于单例模式的饿汉式,即一上来实例化就开始分配数组大小,为其分配空间,每次扩容为1.5倍(add()->grow()),即采用的是原数据+原数据右移一位(即位移运算),即缩小0.5(1+0.5=1.5);jdk8类似于单例模式的懒汉式,需要使用的时候才去分配数组大小,相对于jdk7节省内存资源),由于采用动态数组,它的优点为查询快(通过索引),删除和添加效率不高。(注:使用频率高)时间复杂度:增加和删除:O(n) 查找:O(1)

简单模拟

package com.dy.ArrayList;

public class MyArrayList {

	// 解决数组定长和类型的问题
	
	private Object[] elementData;  // Object类型的数组
	
	private int size;	// 定义长度
	
	// 创建对象初始化数组长度
	public MyArrayList() {
		elementData = new Object[10];
	}

	public void add(Object obj) {
		// 数组扩容机制
		// 数组超出长度需要为其扩容  即重新拷贝一个数组 使其容量加大   将原数据拷贝其新数组
		if (size >= elementData.length) {
			// 创建新数组  增加其容量
			Object[] temp = new Object[elementData.length * 2];
			// 原数组的值复制到新数组
			System.arraycopy(elementData, 0, temp, 0, elementData.length);
			elementData = temp;
		}
		
		elementData[size++] = obj;
	}
	
	public int size() {
		return size;
	}
}

// 测试类
public class MyArrayListTest {
	public static void main(String[] args) {
		MyArrayList myArrayList = new MyArrayList();
		myArrayList.add(1);
		myArrayList.add(2);
		myArrayList.add(3);
		myArrayList.add(4);
		myArrayList.add(5);
		myArrayList.add(6);
		myArrayList.add(7);
		myArrayList.add(8);
		myArrayList.add(9);
		myArrayList.add(10);
		myArrayList.add(11);
		
		System.out.println(myArrayList.size());
	}
}

线程安全分析

观察底层代码发现不同于Vector(底层加入了synchronized线程安全,效率低),ArrayList类属于线程不安全的,效率较高,我们可以通过测试,观察下列测试代码

public class UnsafeList_1 {

	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		// 线程不安全
		// 解决:可以加锁,但是性能相应的降低了
		for (int i = 0; i < 10000; i++) {
			new Thread(() -> {
				list.add(Thread.currentThread().getName());
			}).start();
		}
		/*
		// 加同步锁解决线程不安全
		for (int i = 0; i < 10000; i++) {
			new Thread(()->{
				// 加同步锁
				synchronized (list) {
					list.add(Thread.currentThread().getName());
				}
			}).start();
		}
		*/
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println(list.size());
	}

}

// 观察测试结果list.size()<10000

LinkedList

源码分析

  1. add(E e) // 添加数据
    在这里插入图片描述
  2. Node:成员变量有prev(指向前一个节点的指针),element(数据域),next(指向后一个节点的指针),可以明白LinkedList底层是双向链表结构
    在这里插入图片描述
    在这里插入图片描述

综合分析:LinkedList底层采用的是数据结构中的双向链表(从prev和next可以看出),由于采用的是链表的数据结构,即它的优点删除和添加效率高(只需要移动指针),但是查询速度慢(类似于金链子)
时间复杂度:增加和删除:O(1) 查找:O(n)

简单模拟

public class Node {
	
	public Object obj; // 保存当前节点的数据(数据域)

	public Node prev;	// 前驱节点
	
	public Node next;	// 后继节点

	public Node() {
		super();
	}

	public Node(Object obj, Node prev, Node next) {
		super();
		this.obj = obj;
		this.prev = prev;
		this.next = next;
	}
	
	
	public void setObj(Object obj) {
		this.obj = obj;
	}
}
package com.dy.LinkedList;

public class MyLinkedList {
	// 底层其实内部类的写法
	private Node first;
	
	private Node last;
	
	private int size;
	
	// 链表添加节点
	public void add(Object obj) {
		Node node = new Node();
		if (first == null) {
			// 第一个节点不存在  
			node.prev = null;
			node.next = null;
			node.setObj(obj);
			first = node;
			last = node;
		} else {
			// 第一个结点存在,为其添加后继节点
			node.prev = last;
			node.next = null;
			node.setObj(obj);
			last.next = node;	// 类似于指针连接前后结点
			last = node;   // 此时的last节点为新添加的节点
		}
		size++;
	}
	
	public int size() {
		return size;
	}
}

// 测试类
public class MyLinkedListTest {
	public static void main(String[] args) {
		MyLinkedList list = new MyLinkedList();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		
		System.out.println(list.size());
	}
}

线程安全分析

LinkedList同ArrayList一样是线程不安全的,代码测试和ArrayList大同小异,此时我就不演示了,怎样保证高并发情况下使用这两种集合安全也是后话了,这里不做讨论

TODO:思考

通过比较ArrayList和LinkedList的优缺点,我们可以发现ArrayList由于采用的数组,优点为查询快(通过数组索引),删除和添加效率不高
而LinkedList,它的删除和添加效率高(只需要移动指针),但是查询速度慢------->此时我们不妨想想是否有一种结构能综合两者的优点勒?数组+链表是否就可以勒?后续的HashMap就采用数组+链表(jdk7)+(jdk8+红黑树)…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值