您的位置:首页 > 编程语言 > Java开发

自己理解的java.util.ArrayList(二)实现类

2011-07-04 14:50 453 查看
package myList;

import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Iterator;

/**
* 一个模拟arraylist的简单的集合类
*
* @author 姜侠
*
* @param <E>
*/
public class MyArrayList<E> implements MyList<E>, java.io.Serializable {

private static final long serialVersionUID = 298503308405784327L;

/*
* 在设计一个动态的数组的时候,其本质就是一个数组,
* 所以,该类中应该存在至少2个属性,
* 1.数组elementData
* 2.数组实际大小size
*/

/**
* 数组 transient修饰符:被修饰对象在流的传输过程中不会被保留
* (被修饰对象其类必须实现java.io.Serializable接口)
*elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,
*这个楼主一定是明白的,不用多解释。假如现在实际有了5个元素,而elementData的大小可能是10,
*那么在序列化时只需要储存5个元素,数组中的最后五个元素是没有实际意义的,不需要储存。
*elementData设计为transient,然后在writeObject方法中手动将其序列化,
*并且只序列化了实际存储的那些元素,而不是整个数组
* (实际是重构一个数组使其大小=数据个数)
*/
@SuppressWarnings("unused")
private transient Object[] elementData;

/**
* 数组实际大小(size=数据个数)
*/
@SuppressWarnings("unused")
private int size;

/**
* 记录动态数组重构的次数
*/
private transient int modCount = 0;

/*
* 动态数组的第一次体验就是在创建的时候,
* 我们无需给定数组的大小就可直接创建出我们想要的数组;
* 这都归功于动态数组中的构造方法。
* 我们的构造方法将设置2个
* 1.无参构造,但是数组的声明必须需要一个初始大小,所以我们将在无参构造中给数组一个初始值
* 2.有参构造(数组大小),有时候我们知道数据的个数,
* 所以想手动的设置数组的大小,以减少动态数组在创建数组时候的开销
* 3.有时我们会想到将一个数组转换成一个动态的数组
*/

/**
* 无参构造,但是数组的声明必须需要一个初始大小,
* 所以我们将在无参构造中给数组一个初始值
*/
public MyArrayList() {
this(10);
}

/**
* 有参构造(数组大小),有时候我们知道数据的个数,
* 所以想手动的设置数组的大小,以减少动态数组在创建数组时候的开销
* @param elementSize
*            设置数组大小
*/
public MyArrayList(int elementSize) {
if (elementSize < 0) {
throw new IllegalArgumentException("您的数组大小设置有误: " + elementSize);
} else {
this.elementData = new Object[elementSize];
}
}

/**
* 将动态数组的容量设置为实际数组的大小(容量 = 实际大小)
*/
public void trimToSize() {
this.modCount++;
int oldElementSize = this.elementData.length;
if (this.size < oldElementSize) {
// Arrays.copyOf()与system.arraycopy()作用一样,只是arraycopy()需要指定原数组,
//原数组起始位置,目的数组和目的数组放置的起始位置,复制长度
// 显然比较死板,所以用copyOf()直接将目的数组和复制长度传入进行全部复制
this.elementData = Arrays.copyOf(this.elementData, size);//jdk1.6新添方法
}
}

/**
* 确定动态数组容量 如果数组当前容量不够装载数据,则进行扩容
* @param minCapacity
*            实际大小+1(表示添加的数据坐标)
*/
public void ensureCapacity(int minCapacity) {
this.modCount++;
// 拿到当前数组长度
int oldElementSzie = this.elementData.length;
// 最小容量与当前数组长度对比
// 如果最小容量>当前数组长度,根据黄金分割逆向思维,创建新的数组长度来重构数组
if (minCapacity > oldElementSzie) {
int newElementSize = (oldElementSzie * 3) / 2 + 1;
// 如果最小容量>新数组长度,则将新数组长度=最小容量,因为最小容量通常是接近的大小,所以这是一个双赢
if (minCapacity > newElementSize) {
newElementSize = minCapacity;
}
this.elementData = Arrays.copyOf(this.elementData, newElementSize);
}

}

@Override
public int size() {
return this.size;
}

@Override
public boolean isEmpty() {
return this.size == 0;
}

@Override
public boolean contains(Object obj) {
return indexOf(obj) >= 0;
}

@Override
public Iterator<E> iterator() {
return null;
}

@Override
public Object[] toArray() {
return java.util.Arrays.copyOf(elementData, size);
}

@Override
public boolean add(E e) {
// 先判断是否进行扩充
this.ensureCapacity(this.size + 1);
// 添加数据
this.elementData[size++] = e;
return true;
}

@Override
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;
}

@Override
public boolean containsAll(MyList<E> list) {
int temp = 0;
for (int i = 0; i < list.size(); i++) {
if (this.contains(list.get(i))) {
temp++;
}
}
if (temp == list.size()) {
return true;
}
return false;
}

@Override
public boolean removeAll(MyList<E> list) {
for (int i = 0; i < list.size(); i++) {
if (this.contains(list.get(i))) {
this.remove(list.get(i));
}
}
return true;
}

@Override
public boolean addAll(MyList<E> list) {
int numNew = list.size();
// 是否扩容
ensureCapacity(size + numNew); // Increments modCount
// 元素右移
System.arraycopy(list.toArray(), 0, elementData, size, numNew);
// 更新数组实际大小
size += numNew;
return numNew != 0;
}

@Override
public boolean addAll(int index, MyList<E> list) {
// 判断索引是否符合要求
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
+ size);

int numNew = list.size();
// 是否扩容
ensureCapacity(size + numNew); // Increments modCount

int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);

System.arraycopy(list.toArray(), 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}

@Override
public boolean retainAll(MyList<E> list) {
// 判断参数数组是否为空,如果为空则清空elementData
if (list.size() == 0) {
this.clear();
}
Object[] newObjs = new Object[list.size()];
int temp = 0;// 判断交集是否为空
// 遍历参数数组
for (int i = 0; i < list.size(); i++) {
// 与数组中的每一个元素进行对比
// 如果有相同的元素,则创建一个新的elementData,将一致的数据放入新的数组中
if (this.contains(list.get(i))) {
newObjs[i] = list.get(i);
temp++;
}
}
if (temp == 0) {
this.clear();
} else {
this.elementData = Arrays.copyOf(newObjs, newObjs.length);
this.size = newObjs.length;
}
return true;
}

@Override
public void clear() {
// 重构数组次数+1
modCount++;
// 遍历数组,就所有的元素设为空
for (int i = 0; i < size; i++)
elementData[i] = null;
// 数组实际大小为0
size = 0;
}

@Override
publi
4000
c E get(int index) {
rangeCheck(index);
return (E) elementData[index];
}

@Override
public E set(int index, E element) {
rangeCheck(index);
Object oldElement = this.elementData[index];
this.elementData[index] = element;
return (E) oldElement;
}

@Override
public void add(int index, E element) {
// 判断索引是否符合要求
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
+ size);

// 判断是否需要扩容
ensureCapacity(size + 1); // Increments modCount!!
// 将元素按照指定索引右移(实现数组复制)
System.arraycopy(elementData, index, elementData, index + 1, size
- index);
// 添加新元素
elementData[index] = element;
// 跟新数组实际大小
size++;
}

@Override
public E remove(int index) {
// 判断索引是否越界
rangeCheck(index);
// 增加更改次数
modCount++;
// 获取index指定的元素
E oldValue = (E) elementData[index];

// 获取该元素后一个索引
int numMoved = size - index - 1;
// 判断如果索引大于0,则存在元素,将元素左移(其实实现了数组复制)
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work

return oldValue;
}

@Override
public int indexOf(Object o) {
// 判断对象是否为空
// 如果为空则循环遍历数组,对比那个元素是空,返回第一个匹配的元素的索引index
if (o == null) {
for (int i = 0; i < this.size; i++) {
if (this.elementData[i] == null) {
return i;
}
}
} else {
// 如果不为空则循环遍历数组,对比每一个元素,返回第一个匹配的元素的索引index
for (int i = 0; i < this.size; i++) {
if (this.elementData[i].equals(o)) {
return i;
}
}
}
// 否则返回-1
return -1;
}

@Override
public int lastIndexOf(Object o) {
// 判断对象是否为空
// 如果为空则循环遍历数组,对比那个元素是空,返回第一个匹配的元素的索引index
if (o == null) {
for (int i = this.size - 1; i >= 0; i--) {
if (this.elementData[i] == null) {
return i;
}
}
} else {
// 如果不为空则循环遍历数组,对比每一个元素,返回第一个匹配的元素的索引index
for (int i = this.size - 1; i >= 0; i--) {
if (this.elementData[i].equals(o)) {
return i;
}
}
}
// 否则返回-1
return -1;
}

@Override
public Object[] subList(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException("您的开始下标与结束小标不正确: fromIndex = "
+ fromIndex + "toIndex = " + toIndex);
}
Object[] newObjs = new Object[toIndex - fromIndex];
int j = 0;
for (int i = fromIndex; i <= toIndex; i++) {
newObjs[j] = this.elementData[i];
j++;
}
return newObjs;
}

/**
* 判断参数索引是否大于实际数组的大小
*
* @param index
*/
private void rangeCheck(int index) {
if (index >= this.size) {
throw new IllegalArgumentException("您的坐标已超出数组大小: size = "
+ this.size + "index = " + index);
}
}

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;
}

public String toString() {
this.trimToSize();
StringBuffer str = new StringBuffer();
str.append("[");
for (int i = 0; i < this.elementData.length; i++) {
if (i == this.elementData.length - 1) {
str.append(this.elementData[i]);
} else {
str.append(this.elementData[i] + ",");
}

}
str.append("]");
return str.toString();
}

private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();

// Write out array length
s.writeInt(elementData.length);

// Write out all elements in the proper order.
for (int i = 0; i < size; i++)
s.writeObject(elementData[i]);

if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}

}

private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();

// Read in array length and allocate array
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength];

// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
a[i] = s.readObject();
}

public int getModCount() {
return modCount;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息