栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【JDK源码】ArrayList

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【JDK源码】ArrayList

一、ArrayList概述

数组:一旦初始化长度就不可以发生变化。

增删慢:每次增删元素,都需要改变数组的长度,且移动元素的位置。查询快:数组在内存中是一块连续的空间,可根据地址+索引的方式快速获取对应位置上的元素。

ArrayList:List接口的大小可变数组的实现。

ArrayList底层的数据结构就是数组,数组元素类型为Object类型。对ArrayList类的实例的所有的操作,在底层都是基于数组的。

二、 ArrayList继承关系

2.1 Serializable标记性接口 2.1.1 Serializable介绍

类的序列化由实现java.io.Serializable接口的类启用。 不实现此接口的类将不会使任何状态序列化或反序列化。 可序列化类的所有子类型都是可序列化的。 序列化接口没有方法或字段,仅用于标识可串行化的语义。

序列化:将对象的数据写入到文件(写对象)。反序列化:将文件中对象的数据读取出来(都对象)。 2.1.2 Serializable源码

public interface Serializable {
	// 该接口仅用于标识,没有方法和字段
}
2.2 Cloneable标记性接口 2.2.1 Cloneable介绍

一个类实现Cloneable接口,以指示Object.clone()方法,该方法对于该类的实例进行现场复制是合法的。

在不实现Cloneable接口的实例上调用对象的克隆方法导致抛出异常CloneNotSupportedException 。

2.2.2 Cloneable源码
public interface Cloneable {
	// 该接口没有字段和方法名
}
2.2.3 克隆的前提条件

被克隆对象所在的类必须实现Cloneable接口。必须重写clone()方法。 2.2.4 ArrayList中的clone()方法源码

public Object clone() {
    try {
    	// 调用Object中的clone()
        ArrayList v = (ArrayList) super.clone(); 
        
        // 将ArrayList对象中的元素,拷贝成长度相同的Object[] elementData数组。
        v.elementData = Arrays.copyOf(elementData, size);
        
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}
2.2.5 浅克隆与深克隆

    浅克隆

    直接调用父类Object类的clone()方法。

    局限性:基本数据类型可以达到完全复制。但是引用数据类型不可以,它们会相互影响。

    原因:引用数据类型仅仅克隆了一份引用(即地址),当它的值发生改变时,被克隆对象的属性值也会发生改变。

    深克隆

    不能直接调用父类Object类的clone()方法,需要程序员手动重写。既要克隆该对象,也要更深一步依次克隆对象的所有引用数据类型的属性,再将属性重写赋值。

    深克隆出对象中的所用数据,与原来被克隆对象中的数据不会相互影响,彻底分离。

@Override
public Object clone() throws CloneNotSupportedException {
	// 浅克隆
	//return super.clone(); 

	// 深克隆
	Student stu = (Student) super.clone(); // 将对象克隆
	Skill skill = (Skill)this.skill.clone(); // 将对象的引用数据类型的属性克隆
	stu.setSkill(skill); // 将属性重新赋值
	return stu;
}
2.3 RandomAccess标记性接口 2.3.1 RandomAccess介绍

List实现使用的标记界面,表明它们支持快速(通常为恒定时间)随机访问。 此接口的主要目的是允许通用算法更改其行为,以便在应用于随机访问列表或顺序访问列表时提供良好的性能。

如果一个List实现了这个接口,则随机访问比顺序访问更快。

随机访问列表

for (int i=0, n=list.size(); i < n; i++)
	list.get(i); 

顺序访问列表

for (Iterator i=list.iterator(); i.hasNext(); )
	i.next(); 
2.3.2 RandomAccess源码
public interface RandomAccess {
	// 该接口没有字段和方法名
}
2.4 AbstractList抽象类

该类提供了List接口的骨架实现。

三、ArrayList源码分析 3.1 类的属性
// 序列化ID
private static final long serialVersionUID = 8683452581122892189L;

// 默认初始化容量为10
private static final int DEFAULT_CAPACITY = 10;

// 容量大小为0的空实例的共享数组/
 private static final Object[] EMPTY_ELEMENTDATA = {};

// 默认容量大小的空实例的共享数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};


transient Object[] elementData; 

// ArrayList的实际大小(数组包含的元素个数/实际数据的数量)默认为0
private int size;
3.2 构造器 3.2.1 ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
    	// 指定容量
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
    	// 容量大小为0
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
    	// 指定容量不合法,抛出异常
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
    }
}
3.2.2 ArrayList()
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
3.2.3 ArrayList(Collection c)
public ArrayList(Collection c) {
    Object[] a = c.toArray(); // 将集合c装成数组
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
        	// 数组的创建和拷贝
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // 集合c为空
        elementData = EMPTY_ELEMENTDATA;
    }
}
3.3 主要方法 3.3.1 get(int index)
public E get(int index) {
	// 检查索引范围
    rangeCheck(index);
    // 返回指定位置元素
    return elementData(index);
}



private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}


@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
3.3.2 set(int index, E element)
public E set(int index, E element) {
    rangeCheck(index); // 越界检查
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}
3.3.3 grow(int minCapacity)
private void grow(int minCapacity) {
	// overflow-conscious code
	// 获取当前数组的容量
	int oldCapacity = elementData.length;
	// 扩容。新容量 = 旧容量 + 旧容量/2
	int newCapacity = oldCapacity + (oldCapacity >> 1);

	// 扩容后的新容量 小于 所需最小容量
	if (newCapacity - minCapacity < 0)
	// 将容量再次扩容成所需最小容量
	newCapacity = minCapacity;
	
	// 扩容后的新容量 大于 最大容量临界值
	if (newCapacity - MAX_ARRAY_SIZE > 0)
	// 再次扩容
	newCapacity = hugeCapacity(minCapacity);
	// 拷贝数组
	elementData = Arrays.copyOf(elementData, newCapacity);
}
3.3.4 add(E e)
public boolean add(E e) {
	// 确保容量,容量不够需扩容
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}
	
private void ensureCapacityInternal(int minCapacity) {
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
	
// 确保容量。容量不够就扩容。
private void ensureExplicitCapacity(int minCapacity) {
	modCount++; // 操作次数+1
	
	// 所需最小容量 大于 数组长度
	if (minCapacity - elementData.length > 0)
	grow(minCapacity); // 扩容
}

3.3.5 add(int index, E element)
    
    public void add(int index, E element) {
    	// 	越界检查
        rangeCheckForAdd(index);
		// 确保容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        
        // 拷贝数组,空出index位置,后面元素后移一位
        // arraycopy(源数组,源数组中元素移动的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
3.3.6 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;
 }

 
 private void fastRemove(int index) {
     modCount++;
     int numMoved = size - index - 1;
     if (numMoved > 0)
         System.arraycopy(elementData, index+1, elementData, index,
                          numMoved);
     elementData[--size] = null; // clear to let GC do its work
 }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/711493.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号