定义两个接口MyList和MyIterator。定义好集合和迭代器的规则(方法只实现增删改查及迭代器)
public interface MyList<E> extends Iterable<E> {
?
boolean add(E e);
?
void add(int index, E e);
?
E remove(int index);
?
boolean remove(Object obj);
?
void clear();
?
boolean contains(Object obj);
?
E get(int index);
?
int index(Object obj);
?
int lastIndexOf(Object obj);
?
MyIterator<E> iterator();
?
MyIterator<E> iterator(int index);
}
import java.util.Iterator;
?
public interface MyIterator<E> extends Iterator<E> {
boolean hasNext();
?
boolean hasPrevious();
?
E next();
?
E previous();
?
int nextIndex();
?
int prevIndex();
?
void add(E e);
?
void remove();
?
void set(E e);
}
对于ArrayList,要对其常量、属性、构造方法、API进行设计
常量:要确定底层数组的最大容量和默认容量
private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_CAPACITY = Ineger.MAX_VALUE - 8;
属性:底层是数组
private Object[] elements;
private int size;
private int modCount; //统计集合结构修改的次数,验证迭代器是否失效
构造方法
public MyArrayList() {
elements = new Object[DEFAULT_CAPACITY];
}
?
public MyArrayList(int initialCapacity) {
if (initialCapacity <= 0 || initialCapacity > MAX_CAPACITY)
throw new IllegalArgumentException("initialCapacity=" + initialCapacity);
elements = new Object[initialCapacity];
}
API:
增: boolean add(E e) void add(int index, E e)
tips:
计算扩容长度时,可以使用移位运算符
在grow()扩容方法中,要记得将elements数组指向已经扩容好的数组
public boolean add(E e) {
add(size, e);
return true;
}
public void add(int index, E e) {
//判断索引是否合法
checkIndexForAdd(index);
//判断是否需要扩容
if (size == elements.length) {
// 计算新数组的容量
int minCapacity = size + 1;
int newCapacity = calculateCapacity(minCapacity);
// 扩容
grow(newCapacity);
}
// 添加元素
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = e;
size++;
modCount++;
}
?
private void grow(int newCapacity) {
Object[] newArr = new Object[newCapacity];
// 复制数据
for (int i = 0; i < size; i++) {
newArr[i] = elements[i];
}
// elements指向新数组
elements = newArr; // Caution!
}
?
private int calculateCapacity(int minCapacity) {
if (minCapacity > MAX_CAPACITY || minCapacity < 0) {
throw new ArrayOverflowException();
}
// 一定容纳下minCapacity个元素
int newLength = elements.length + (elements.length >> 1);
if (newLength > MAX_CAPACITY || newLength < 0) {
newLength = MAX_CAPACITY;
}
// 返回minCapacity和newLength的最大值
return newLength > minCapacity ? newLength : minCapacity;
}
?
private void checkIndexForAdd(int index) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("index=" + index + ", size=" + size);
}
}
删:E remove (int index) boolean remove(Object obj) void clear()
tips:
删除操作所检查的索引范围时[0,size-1],注意与增加操作区分开
clear()中,要把所有元素值置为null,避免内存泄漏
public E remove(int index) {
//首先要检查索引的合法性
checkIndex(index);
E removeValue = (E) elements[index];
//将索引后的元素都前移
for (int i = index; i < size - 1; i++) {
elements[i] = elements[i + 1];
}
elements[--size] = null; //最后一个元素置为null值,避免内存泄漏
modCount++;
return removeValue;
?
}
?
private void checkIndex(int index) {
//,注意检查的值与检查增加的索引值不同。范围[0,size-1]
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("index=" + index + ",size=" + size);
}
public boolean remove(Object obj) {
//这里调用indexOf(obj)就可以找到目标索引。有了索引直接调用remove(index)即可
int index = indexOf(obj);
if (index == -1) return false;
remove(index);
return true;
}
public void clear() {
//把集合中的元素都置为null值
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
modCount++; //修改了集合结构
}
改: E set(int index, E e)
public E set(int index, E e) {
checkIndex(index);
E oldValue = (E) elements[index];
elements[index] = e;
return oldValue;
}
查: int indexOf(Object obj) lastIndexOf(Object obj) boolean contains(Object obj)
E get(int index) boolean isEmpty() int size()
tips:
注意要判断指定对象的值是否为null(分情况),因为List集合是可以存储null元素的。判断的时候也要分情况,看代码吧
public int indexOf(Object obj) {
if (obj == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == null) return i;
}
}
else {
for (int i = 0; i < size; i++) {
if (obj.equals(elements[i])) return i;
}
}
return -1;
}
public int lastIndexOf(Object obj) {
if (obj == null) {
for (int i = size - 1; i >= 0; i--) {
if (obj.equals(elements[i])) return i;
}
}
else {
for (int i = size - 1; i >= 0; i--) {
if (obj.equals(elements[i])) return i;
}
}
return -1;
}
public boolean contains(Object obj) {
return indexOf(obj) != -1;
}
public E get(int index) {
checkIndex(index);
return (E) elements[index];
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
迭代器部分
迭代器使用内部类方式定义
属性
int cursor;
int lastRet = -1; //最近返回元素的索引,-1代表最近未返回元素
int expCount = modCount; //当前集合修改次数为期望次数
构造方法
Itr() {}
?
Itr(int index) {
cursor = index; //将光标置为index
}
API
public boolean hasNext() {
return cursor != size;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E next() {
//判断迭代器是否有效
checkConModException();
//判断光标后面还有元素嘛
if (!hasNext())
throw new NoSuchElementException();
//简化了步骤,返回的是光标经过的值,也就是当前光标后的索引
//lastRet = cursor,然后cursor后移
lastRet = cursor++;
return (E) elements[lastRet];
}
?
private void checkConModException() {
if (expCount != modCount)
throw new ConcurrentModificationException();
}
public E previous() {
checkConModException();
if (!hasPrevious())
throw new NoSuchElementException();
//cursor指向的元素是前面那一个,lastRet要先--在获取
lastRet = --cursor;
return (E) elements[lastRet];
}
public int nextIndex() {
return cursor;
}
public int prevIndex() {
return cursor - 1;
}
public void add(E e) {
checkConModException();
//这里是内部类,调用外部类方法,必须要借助外部类对象
//这里和remove不同,lastRet可能为-1.cursor为0
MyArrayList.this.add(cursor, e); //这里modCount++,修改了集合结构
//修改迭代器属性
expCount = modCount; //通过迭代器修改,允许修改,将expCount的值变为当前修改次数
lastRet = -1; //修改之后,上次返回值索引变为-1
cursor++;
}
public void remove() {
checkConModException();
//判断最近是否有返回元素,因为删除操作必须对最近返回的元素(lastRet)进行删除,光标只负责指向的
if (lastRet == -1)
throw new IllegalArgumentException();
MyArrayList.this.remove(lastRet);
expCount = modCount;
//关于cursor的变化,这里要分正向和逆向遍历讨论。结合画图可以找到对应规律!!
cursor = lastRet; //!!!!!
lastRet = -1;
}
public void set(E e) {
checkConModException();
?
if (lastRet == -1)
throw new IllegalArgumentException();
elements[lastRet] = e;
lastRet = -1;
}
外部类调用了Iterator内部类的两个构造方法对创建Itr对象
public MyIterator<E> iterator() {
return new Itr();
}
public MyIterator<E> iterator(int index) {
checkIndex(index);
return new Itr(index);
}
原文:https://www.cnblogs.com/cranfield/p/13342044.html