`
zy19982004
  • 浏览: 661864 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
F6f66edc-1c1a-3859-b76b-a22e740b7aa7
Hadoop学习
浏览量:251950
社区版块
存档分类
最新评论

容器学习七:ArrayList源码分析

阅读更多

 一.成员变量

	// 在AbstractList里面定义的
	protected transient int modCount = 0;

	// 内部用数组实现
	private transient Object[] elementData;

	private int size;
 

二.构造函数

	// 自己在写代码的时候为了严谨,最好是先判断参数抛出IllegalArgumentException
	public ArrayList(int initialCapacity) {
		super();
		if (initialCapacity < 0)
			throw new IllegalArgumentException("Illegal Capacity: "
					+ initialCapacity);
		this.elementData = new Object[initialCapacity];
	}

	// 初始化容量10
	public ArrayList() {
		this(10);
	}
 

 三.存数据

	//增加数据
	public boolean add(E e) {
		//1.保证容量,size+1和容量比较,看是否有位置插入e
		ensureCapacity(size + 1); // Increments modCount!!
		//2.直接赋值
		elementData[size++] = e;
		return true;
	}

	//在指定位置增加数据
	public void add(int index, E element) {
		if (index > size || index < 0)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		//1.保证容量
		ensureCapacity(size + 1); // Increments modCount!!
		//2.向右移动当前位于该位置的元素(如果有)以及所有后续元素(将其索引加 1)。 
		System.arraycopy(elementData, index, elementData, index + 1, size
				- index);
		//3.将指定的元素插入此列表中的指定位置
		elementData[index] = element;
		size++;
	}
	
	// 检查容量,minCapacity=size+1
	public void ensureCapacity(int minCapacity) {
		modCount++;
		int oldCapacity = elementData.length;
		// 如果超过容量
		if (minCapacity > oldCapacity) {
			Object oldData[] = elementData;
			// 新容量=(老容量 * 3)/2 + 1
			// 如果老容量为10,则新容量为16
			int newCapacity = (oldCapacity * 3) / 2 + 1;
			//newCapacity < minCapacity会产生这样的情况?????
			if (newCapacity < minCapacity)
				newCapacity = minCapacity;
			//复制原数组数据到大小为newCapacity的数组中
			elementData = Arrays.copyOf(elementData, newCapacity);
		}
	}
	
	//替换数据
	public E set(int index, E element) {
		RangeCheck(index);
		//保存index处旧值
		E oldValue = (E) elementData[index];
		//赋新值
		elementData[index] = element;
		return oldValue;
	}
	//下标志检查
	private void RangeCheck(int index) {
		if (index >= size)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
	}
 

四.取数据

	public E get(int index) {
		RangeCheck(index);
		return (E) elementData[index];
	}
	
	// 返回第一次出现o的下标,用equals比较
	// 如果不存在o,返回-1
	public int indexOf(Object o) {
		if (o == null) {
			for (int i = 0; i < size; i++)
				if (elementData[i] == null)
					return i;
		} else {
			for (int i = 0; i < size; i++)
				if (o.equals(elementData[i]))
					return i;
		}
		return -1;
	}

	// 想想为什么不这么实现
	// 上面的实现方式比较次数2+n,下面的比较次数2*n
	public int indexOf(Object o) {
		for (int i = 0; i < size; i++) {
			if (o == null) {
				if (elementData[i] == null)
					return i;
			} else {
				if (o.equals(elementData[i]))
					return i;
			}
		}
		return -1;
	}

	// 从size-1往0遍历
	public int lastIndexOf(Object o) {
		if (o == null) {
			for (int i = size - 1; i >= 0; i--)
				if (elementData[i] == null)
					return i;
		} else {
			for (int i = size - 1; i >= 0; i--)
				if (o.equals(elementData[i]))
					return i;
		}
		return -1;
	}
 

五.删数据

	//移除index处的元素是List接口里新加的方法
	//同Map一样,在插入元素的操作中会扩容,删除元素并不去减容
	public E remove(int index) {
		RangeCheck(index);

		modCount++;
		E oldValue = (E) elementData[index];
		//需要移动的元素个数
		int numMoved = size - index - 1;
		if (numMoved > 0)
			//数组内(间)元素移动,五个参数依次为
			//src - 源数组。
			//srcPos - 源数组中的起始位置。
			//dest - 目标数组。
			//destPos - 目标数据中的起始位置。
			//length - 要复制的数组元素的数量。
			System.arraycopy(elementData, index + 1, elementData, index,
					numMoved);
		//让GC回收因移动空出的数组最后一位
		elementData[--size] = null; 

		return oldValue;
	}
	
	//remove某个元素是Collection接口里的方法
	//同Map一样,在插入元素的操作中会扩容,删除元素并不去减容
	//remove(int index)和remove(Object o)一次只会移除一个元素
	public boolean remove(Object o) {
		if (o == null) {
			for (int index = 0; index < size; index++)
				if (elementData[index] == null) {
					fastRemove(index);
					return true;
				}
		} else {
			for (int index = 0; index < size; index++)
				if (o.equals(elementData[index])) {
					fastRemove(index);
					return true;
				}
		}
		return false;
	}
	
	//把index后的元素移往前移一位
	private void fastRemove(int index) {
		modCount++;
		int numMoved = size - index - 1;
		if (numMoved > 0)
			System.arraycopy(elementData, index + 1, elementData, index,
					numMoved);
		//让GC回收因移动空出的数组最后一位
		elementData[--size] = null; 
	}
 

六.List与Array

	//ArrayList转换成数组
	//将ArrayList内部的数组0到size-1位返回即可
	public Object[] toArray() {
		return Arrays.copyOf(elementData, size);
	}
	
	//ArrayList转换成指定数组a
	public <T> T[] toArray(T[] a) {
		if (a.length < size)
			// Make a new array of a's runtime type, but my contents:
			return (T[]) Arrays.copyOf(elementData, size, a.getClass());
		System.arraycopy(elementData, 0, a, 0, size);
		if (a.length > size)
			a[size] = null;
		return a;
	}
 
2
5
分享到:
评论

相关推荐

    java并发容器CopyOnWriteArrayList实现原理及源码分析

    Java并发容器CopyOnWriteArrayList实现原理及源码分析 Java并发容器CopyOnWriteArrayList是Java并发包中提供的一个并发容器,实现了线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现。...

    java提高篇(二一)-----ArrayList.pdf

    ArrayList 源码分析: ArrayList 底层采用数组实现,所以它的操作基本上都是基于对数组的操作。ArrayList 提供了三个构造函数: 1. ArrayList():默认构造函数,提供初始容量为 10 的空列表。 2. ArrayList(int ...

    免费开源-【Java学习+面试指南】部分内容大部分是Java程序员所需要掌握的核心知识

    Unsafe 详细解Java SPI 机制详解Java语法糖详解集合知识点/面试题总结:Java集合常见知识点&面试题总结(上)(必看)Java集合常见知识点&面试题总结(下)(必看)Java容器使用注意事项总结源码分析:ArrayList核心...

    【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    源码分析: ArrayList 核心源码+扩容机制分析 LinkedList 核心源码分析 HashMap 核心源码+底层数据结构分析 ConcurrentHashMap 核心源码+底层数据结构分析 LinkedHashMap 核心源码分析 CopyOnWriteArrayList 核心...

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识

    源码分析: ArrayList 源码+扩容机制分析 HashMap(JDK1.8)源码+底层数据结构分析 ConcurrentHashMap 源码+底层数据结构分析 IO IO 基础知识总结 IO 设计模式总结 IO 模型详解 并发 知识点/面试题总结 : (必看 ) ...

    「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识 准备 Java 面试,首选.zip

    源码分析 : ArrayList 源码+扩容机制分析 HashMap(JDK1.8)源码+底层数据结构分析 ConcurrentHashMap 源码+底层数据结构分析 IO IO 基础知识总结 IO 设计模式总结 IO 模型详解 并发 知识点/面试题总结 : (必看 ) ...

    JUC并发编程与源码分析视频课.zip

    《JUC并发编程与源码分析视频课》是一门深入探讨Java并发编程的课程,主要聚焦于Java Util Concurrency(JUC)库的使用和源码解析。JUC是Java平台提供的一组高级并发工具包,它极大地简化了多线程编程,并提供了更...

    Java源码分析:集合-容器.pdf

    Vector与ArrayList类似,但它是一个古老的类,是线程安全的,而ArrayList不是。 Queue接口定义了先进先出的队列操作,LinkedList实现了Queue接口,因此可以作为一个队列来使用。除了基本的队列操作外,Java还提供了...

    Java容器总结

    源码分析有助于理解其设计模式和事件驱动机制。 3. **EJB(Enterprise JavaBeans)**:在企业级应用中,EJB容器负责管理事务、安全性和资源,提供服务器端组件的生命周期管理。EJB有三种类型:session beans、...

    毕业设计源码之ArrayList,LinkList链表接口实现.zip

    2. **ArrayList与LinkedList的区别**:对比分析ArrayList和LinkedList在存储结构、空间效率、时间复杂度等方面的差异,学习如何根据需求选择合适的数据结构。 3. **源码阅读**:通过阅读ArrayList和LinkedList的...

    Java容器ArrayList知识点总结

    ArrayList的源码分析可以帮助我们更好地了解ArrayList的实现机制。ArrayList的底层实现使用数组实现,数组的元素类型是Object[]。ArrayList的构造方法中使用了三种不同的数组实现:DEFAULTCAPACITY_EMPTY_...

    java并发源码分析之实战编程

    总之,"java并发源码分析之实战编程"涵盖了许多关键知识点,从基本的线程操作到复杂的并发设计模式,都需要开发者深入学习和实践。通过研究源码,我们可以更深入地理解这些机制的工作原理,从而在实际开发中做出更优...

    javaSourceLearn:jdk源码构建

    List、Set、Map三大接口以及其实现类(ArrayList、LinkedList、HashSet、TreeSet、HashMap、LinkedHashMap等)的源码分析能帮助我们更高效地利用数据结构,优化程序性能。 标签“系统开源”表明这个项目鼓励开放和...

    Java 容器.pdf_电子版pdf版

    源码分析 ArrayList 是一个基于动态数组实现的 List 实现类。它实现了 RandomAccess 接口,因此支持随机访问。ArrayList 的默认大小为 10,添加元素时使用 ensureCapacityInternal() 方法来保证容量足够,如果不够...

    java源码解读-java-src:java源码解读

    源码分析能揭示这些数据结构的工作方式,例如ArrayList的动态扩容策略,HashSet的哈希函数设计,以及HashMap的冲突解决方法。理解这些细节有助于我们在实际编程中选择合适的集合类型,提高数据操作效率。 并发编程...

    JAVA容器效率深度分析List

    本文将深入分析Java中的List接口及其常见的实现类,如ArrayList、LinkedList和Vector,探讨它们的效率差异和适用场景。 首先,List是Java集合框架中的一个重要接口,它扩展了Collection接口,并规定了元素的有序性...

    study1010_bursttpf_java学习_源码.zip

    3. **集合框架**:ArrayList、LinkedList、HashSet、HashMap等容器的使用,以及泛型的理解。 4. **IO流**:学习如何读写文件,理解字节流和字符流的区别,以及缓冲区的概念。 5. **多线程**:线程的创建、同步机制...

    androidjava源码-Android-Knowledge:Android源码和Java知识总结

    - **集合框架**:ArrayList、LinkedList、HashMap等容器的实现细节和性能对比。 - **异常处理**:理解Checked和Unchecked异常,以及如何优雅地处理异常。 - **多线程与并发**:线程的创建、同步机制...

    Java 中模仿源码自定义ArrayList

    通过分析ArrayList的源码,我们可以学习到如何创建一个类似的数据结构,这有助于我们提升对数组、扩容、索引操作等概念的理解。 首先,自定义的MyArrayList类需要一个存储元素的数组,这里选择的是`Object[] ...

Global site tag (gtag.js) - Google Analytics