ArrayList的底层原理是用数组实现的,所以我们就可以自定义实现一个ArrayList,主要实现一些简单的方法,其实有的方法本质上也是数组的拷贝,目的是深入体会底层原理,加深对ArrayList容器的理解。
首先:我们需要一个自定义数组,元素大小,默认容量和有参无参构造方法,以便创建默认或者指定容量大小的容器。
/**
* 自定义数组
*/
private Object[] elementData;
/**
* 数组实际元素大小
*/
private int size;
/**
* 默认容器的容量
*/
private static final int DEFAULT_CAPACITY = 10;
public SXArrayList(){
elementData = new Object[DEFAULT_CAPACITY];
}
public SXArrayList(int capacity){
elementData = new Object[capacity];
}
其次:添加add方法,给容器添加元素。添加元素之前要判断是否需要扩容,扩容的本质也是数组的复制,定义一个更大的数组,再把原来的数组复制过去。什么时候需要扩容呢?就是当容器满了的时候,我们就定义一个新的数组,容量就是旧数组容量+旧数组容量的一半(注意这里是数组容量大小,不是元素大小),这里我们用位运算,效率高,最后把新数组的引用赋给旧数组。
public void add(Object obj){
//如果容量满了 就需要扩容了
if (size == elementData.length){
Object[] newArray = new Object[elementData.length + (elementData.length >> 1)];
System.arraycopy(elementData, 0, newArray, 0, size);
elementData = newArray;
}
elementData[size++] = obj;
}
再次:添加remove移除方法,可以根据索引或者元素内容移除对应的元素。移除等操作前需要判断索引是否合法,移除的本质也是数组的复制,覆盖掉要移除的元素,假如移除的是最后一个元素就可以直接赋值为null就行。根据内容移除就是遍历容器找到内容相等的元素下标再执行remove操作。
/**
* 移除容器中指定索引的元素内容
* @param index 索引
*/
public void remove(int index){
indexCheck(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
elementData[--size] = null;
}
/**
* 移除容器中指定的元素内容
* @param obj 元素内容
*/
public void remove(Object obj){
if (null != obj){
for (int i = 0; i < size; i++) {
if (obj.equals("" + elementData[i])){
remove(i);
break;
}
}
}
}
private void indexCheck(int index){
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("索引不存在:" + index);
}
}
再次:添加set方法,给容器中指定索引设置元素内容。这个也要判断索引是否合法,然后就直接给指定元素重新赋值。这里要重写toString方法,返回一个格式内容字符串,可以用于打印容器内容。
/**
* 给容器中指定索引设置元素内容
* @param index 索引
* @param obj 元素内容
*/
public void set(int index, Object obj){
indexCheck(index);
elementData[index] = obj;
}
/**
* 重写toString方法
* @return 返回元素内容
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(elementData[i]).append(",");
}
sb.setCharAt(sb.length()-1,']');
return sb.toString();
}
最后:添加get,size等简单的方法,最后main方法简单测试一下,结果正常,后期还可以完善添加泛型,加深理解和记忆。
public static void main(String[] args) {
SXArrayList list = new SXArrayList();
for (int i = 0 ;i < 26;i++){
list.add((char)(i+97));
}
System.out.println(list);
list.remove(25);
System.out.println(list);
list.remove("d");
System.out.println(list);
System.out.println(list.get(2));
list.set(0,"aa");
System.out.println(list);
}
[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y]
[a,b,c,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y]
c
[aa,b,c,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y]
完整代码如下:
/**
* 手工实现ArrayList
*/
public class SXArrayList {
/**
* 自定义数组
*/
private Object[] elementData;
/**
* 数组实际元素大小
*/
private int size;
/**
* 默认容器的容量
*/
private static final int DEFAULT_CAPACITY = 10;
public SXArrayList(){
elementData = new Object[DEFAULT_CAPACITY];
}
public SXArrayList(int capacity){
elementData = new Object[capacity];
}
/**
* 获取容器元素大小
* @return 返回大小
*/
public int size(){
return size;
}
/**
* 判断容器里是否有元素内容
* @return 返回是否
*/
public boolean isEmpty(){
return size == 0;
}
/**
* 给容器添加元素
* @param obj 添加的元素内容
*/
public void add(Object obj){
//如果容量满了 就需要扩容了
if (size == elementData.length){
Object[] newArray = new Object[elementData.length + (elementData.length >> 1)];
System.arraycopy(elementData, 0, newArray, 0, size);
elementData = newArray;
}
elementData[size++] = obj;
}
/**
* 获取容器中指定索引的元素内容
* @param index 索引
* @return 返回元素内容
*/
public Object get(int index){
indexCheck(index);
return elementData[index];
}
/**
* 移除容器中指定索引的元素内容
* @param index 索引
*/
public void remove(int index){
indexCheck(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
elementData[--size] = null;
}
/**
* 移除容器中指定的元素内容
* @param obj 元素内容
*/
public void remove(Object obj){
if (null != obj){
for (int i = 0; i < size; i++) {
if (obj.equals("" + elementData[i])){
remove(i);
break;
}
}
}
}
/**
* 给容器中指定索引设置元素内容
* @param index 索引
* @param obj 元素内容
*/
public void set(int index, Object obj){
indexCheck(index);
elementData[index] = obj;
}
/**
* 重写toString方法
* @return 返回元素内容
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(elementData[i]).append(",");
}
sb.setCharAt(sb.length()-1,']');
return sb.toString();
}
/**
* 检查索引是否越界
* @param index 索引
*/
private void indexCheck(int index){
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("索引不存在:" + index);
}
}
}