以下是模拟实现ArrayLis增删改查功能t的代码:
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* 创建模拟ArrayList集合的类并为了模拟迭代器实现Iterable接口
*
* @param <AnyType>
*/
public class MyArrayList<AnyType> implements Iterable<AnyType> {
//定义集合初始容量大小,设为10
private static final int DEFAULT_CAPACITY = 10;
//定义集合的元素个数
private int theSize;
// 定义一个数组,存储的数据类型根据范型存储
private AnyType[] theArr;
// 无参构造调用集合初始化方法
public MyArrayList() {
init();
}
// 集合初始化方法,清空元素,设容量为10
private void init() {
theSize = 0;
alterCapacity(DEFAULT_CAPACITY);
}
// 改变集合容量大小的方法,参数是容量的大小
public void alterCapacity(int newCapacity) {
if (newCapacity < theSize) {
return;
}
AnyType[] old = theArr;
theArr = (AnyType[]) new Object[newCapacity];
for (int i = 0; i < size(); i++) {
theArr[i] = old[i];
}
}
//获取集合中元素个数
public int size() {
return theSize;
}
//判断集合中是否有元素
public boolean isEmpty() {
return size() == 0;
}
//通过下标获取元素
public AnyType get(int index) {
if (index < 0 || index >= size()) {
throw new ArrayIndexOutOfBoundsException();
}
return theArr[index];
}
//通过下标更改集合中的元素并返回被替换的元素
public AnyType set(int index, AnyType newElement) {
if (index < 0 || index >= size()) {
throw new ArrayIndexOutOfBoundsException();
}
AnyType old = theArr[index];
theArr[index] = newElement;
return old;
}
//在最后增加一个元素
public boolean add(AnyType element) {
add(size(), element);
return true;
}
//扩容大小+1是为了避免原集合为空的情况
//通过下标增加元素的方法,如果是插入集合中,次数多了for循环是低效的
public void add(int index, AnyType newElement) {
if (theArr.length == size()) {
alterCapacity(size() * 2 + 1);
}
for (int i = theSize; i > index; i--) {
theArr[i] = theArr[i - 1];
}
theArr[index] = newElement;
theSize++;
}
//通过下标删除,每次删除都要经过for循环,所以删除方法也不高效
public AnyType remove(int index) {
AnyType removeElement = theArr[index];
for (int i = index; i < size() - 1; i++) {
theArr[i] = theArr[i + 1];
}
theSize--;
return removeElement;
}
@Override
public Iterator<AnyType> iterator() {
return new MyArrayListIterator();
}
//定义内部类实现迭代器
private class MyArrayListIterator implements Iterator<AnyType> {
//初始下标
private int current = 0;
//判断是否有元素
@Override
public boolean hasNext() {
return current < size();
}
//返回下标位置的元素
@Override
public AnyType next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return theArr[current++];
}
//类名.this.成员 是内部类调用外部类成员的方法
@Override
public void remove() {
MyArrayList.this.remove(--current);
}
}
}
只是简单的模拟,但是有个需要注意的地方:我们用迭代器迭代集合的时候是不可以中途用集合的对象去删除元素的。如以下代码会报ConcurrentModificationException异常:
ArrayList<String> arr = new ArrayList<>();
arr.add("111");
arr.add("222");
arr.add("333");
Iterator<String> iterator = arr.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
arr.remove(1);
}
结果是:
111
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
为了更加直观的分析再加两个输出语句:
ArrayList<String> arr = new ArrayList<>();
arr.add("111");
arr.add("222");
arr.add("333");
Iterator<String> iterator = arr.iterator();
while (iterator.hasNext()){
System.out.println(1);
String next = iterator.next();
System.out.println(next);
arr.remove(1);
System.out.println(2);
}
结果是:
1
111
2
1
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
试着用try-catch-finally语句块模拟两次循环再捕获:
for (int i=0;i<2;i++){
iterator.hasNext();
String next = null;
try {
next = iterator.next();
System.out.println(next);
arr.remove(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(arr.size());
}
}
结果是:
111
2
2
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
也就是说执行remove方法时集合中的元素是被删除成功的,查看抛出异常的源码:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
通过modCount和expectedModCount变量保证了迭代器在迭代过程中的完整性,分析:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
这是ArrayList中实现Iterator的内部类,和我模拟的MyArrayListIterator类类似,调用迭代器时expectedModCount被外部类(ArrayList)的modCount赋值初始化一次,但是操作集合对象的remove方法时modCount会+1,next方法会调用checkForComodification方法判断,所以抛出异常;
分析ArrayList的优缺点:
优点:
1、根据下标遍历元素效率较高。
2、根据下标访问元素效率较高。
3、在数组的基础上封装了对元素操作的方法。
4、可以自动扩容。
缺点:
1、插入和删除的效率比较低。
2、根据内容查找元素的效率较低。
扩容规则:每次扩容现有容量的50%。