-
简介(Introduction)
上篇文章主要介绍了ArrayList自行模仿建立的方式,那么,其实这个类不是一次性就那么完美的,现在做一个一步步变成那样完整的ArrayList的版本升级测试.
期间会阐述企业级在使用类的时候的常用做法.
版本中将去掉接口和继承,让你看到一个极简模式的ArrayList.
其实源码就是对于Java这门语言的概念的应用,你的理解可能只是书上,教程上最简单的理解,但是,并没有进行深入的理解,而源码要面向各种环境,各种可能性的应用而进行的设计.
随着Java开发年头的增加,你对基础概念的理解也将逐渐增加,就像三重境界
看山是山,看水是水;
看山不是山,看水不是水;
看山还是山,看水还是水
而Java的理解也是
一切皆为对象;
一切皆为对象;
一切皆为对象 -
快速上手(Getting Started)
建立一个基础版的ArrayList,理解Object[]的特性,对于Object型数组的应用加深理解
建立源码1 /** 自定义ArrayList极简版 / 2 public class MySelfArrayList { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 49 elementData = new Object[DEFAULT_CAPACITY]; 50 51 // 封装toString方法返回结果值 52 stringBuilder = new StringBuilder(); 53 } 54 55 56 /** 57 * 数组添加元素方法 58 * 59 * @param object 任意类型的数据添加到数组中 60 */ 61 public void add(Object object) { 62 63 // 每次调用这个方法的时候,就像数组中添加索引值的元素 64 elementData[size++] = object; 65 } 66 67 68 /** 69 * 重写toString方法,打印数组元素 70 * 71 * @return 数组元素样式 72 */ 73 @Override 74 public String toString() { 75 76 stringBuilder.append("MySelfArrayList : {"); 77 stringBuilder.append("elementData="); 78 79 for (int i = 0; i < size; i++) { 80 stringBuilder.append(elementData[i] + ","); 81 } 82 83 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 84 85 stringBuilder.append("}"); 86 87 return stringBuilder.toString(); 88 } 89 }
测试简单实体类
1 public static void main(String[] args) { 2 3 MySelfArrayList mySelfArrayList = new MySelfArrayList(); 4 5 mySelfArrayList.add("A"); 6 mySelfArrayList.add("B"); 7 8 9 System.out.println(mySelfArrayList.toString()); 10 }
-
入门篇(Basics)
-
环境准备(Prerequisite)
JDK环境:JDK1.8
工具:IDEA 2019
需要理解数组的概念,详见:https://www.cnblogs.com/liuyangfirst/p/12364850.html
理解StringBuilder使用方法,详见:https://www.cnblogs.com/liuyangfirst/p/12829294.html
理解toString()使用方法:https://www.cnblogs.com/liuyangfirst/p/12255687.html
-
-
进阶篇(Advanced)
1、添加自定义泛型
建立源码
1 /** 自定义ArrayList,添加泛型 / 2 public class MySelfArrayList<ME> { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 49 elementData = new Object[DEFAULT_CAPACITY]; 50 51 // 封装toString方法返回结果值 52 stringBuilder = new StringBuilder(); 53 } 54 55 56 /** 57 * 数组添加元素方法 58 * 59 * @param object 任意类型的数据添加到数组中 60 */ 61 public void add(Object object) { 62 63 // 每次调用这个方法的时候,就像数组中添加索引值的元素 64 elementData[size++] = object; 65 } 66 67 68 /** 69 * 重写toString方法,打印数组元素 70 * 71 * @return 数组元素样式 72 */ 73 @Override 74 public String toString() { 75 76 stringBuilder.append("MySelfArrayList : {"); 77 stringBuilder.append("elementData="); 78 79 for (int i = 0; i < size; i++) { 80 stringBuilder.append(elementData[i] + ","); 81 } 82 83 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 84 85 stringBuilder.append("}"); 86 87 return stringBuilder.toString(); 88 } 89 }
测试
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("A"); 6 mySelfArrayList.add("B"); 7 8 9 System.out.println(mySelfArrayList.toString()); 10 11 12 }
2、添加扩容机制
扩容机制:通过定义新的更大的数组,将旧数组中的内容拷贝到新数组,来实现扩容
两个核心问题:
什么时候扩容?
当默认数组或自定义数组的最大值无法承载添加的元素数量的时候,进行扩容.比如:默认是10,添加第11个元素,就会报错,所以此时就要修改代码,以便适应更多情况.
怎么扩容?
(1)定义一个更大的数组,比如建立一个二倍大小的数组,为了提高效率,可以采用左移的方式,左移一位<<1.源码中是原长度+原长度的一半,即如果是原长度10,扩容后就是15.
(2)使用拷贝机制,将原来的数组拷贝到新数组.
拷贝机制详见:https://www.cnblogs.com/liuyangfirst/p/12364850.html
建立源码
1 /** 自定义ArrayList,添加扩容机制 / 2 public class MySelfArrayList<ME> { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 49 elementData = new Object[DEFAULT_CAPACITY]; 50 51 // 封装toString方法返回结果值 52 stringBuilder = new StringBuilder(); 53 } 54 55 56 /** 57 * 数组添加元素方法 58 * 59 * @param object 任意类型的数据添加到数组中 60 */ 61 public void add(Object object) { 62 63 // 当传入的元素个数跟默认或自定义的长度相等的时候采用扩容机制 64 if (size == elementData.length) { 65 66 //定义一个更大的数组 67 Object[] newArray = new Object[elementData.length + (elementData.length >> 1)]; 68 69 // 拷贝旧的数组到新的数组中 70 System.arraycopy(elementData, 0, newArray, 0, elementData.length); 71 72 // 将新数组结果赋值给创建的数组 73 elementData = newArray; 74 } 75 76 77 // 每次调用这个方法的时候,就像数组中添加索引值的元素 78 elementData[size++] = object; 79 } 80 81 82 /** 83 * 重写toString方法,打印数组元素 84 * 85 * @return 数组元素样式 86 */ 87 @Override 88 public String toString() { 89 90 stringBuilder.append("MySelfArrayList : {"); 91 stringBuilder.append("elementData="); 92 93 for (int i = 0; i < size; i++) { 94 stringBuilder.append(elementData[i] + ","); 95 } 96 97 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 98 99 stringBuilder.append("}"); 100 101 return stringBuilder.toString(); 102 } 103 }
测试
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 for (int i = 0; i < 20; i++) { 6 mySelfArrayList.add("B"); 7 } 8 9 10 System.out.println(mySelfArrayList.toString()); 11 12 13 }
3、添加Object的get和set方法
1 /** 自定义ArrayList,添加Object的get和set方法 / 2 public class MySelfArrayList<ME> { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 49 elementData = new Object[DEFAULT_CAPACITY]; 50 51 // 封装toString方法返回结果值 52 stringBuilder = new StringBuilder(); 53 } 54 55 56 /** 57 * 数组添加元素方法 58 * 59 * @param object 任意类型的数据添加到数组中 60 */ 61 public void add(Object object) { 62 63 // 当传入的元素个数跟默认或自定义的长度相等的时候采用扩容机制 64 if (size == elementData.length) { 65 66 //定义一个更大的数组 67 Object[] newArray = new Object[elementData.length + (elementData.length >> 1)]; 68 69 // 拷贝旧的数组到新的数组中 70 System.arraycopy(elementData, 0, newArray, 0, elementData.length); 71 72 // 将新数组结果赋值给创建的数组 73 elementData = newArray; 74 } 75 76 77 // 每次调用这个方法的时候,就像数组中添加索引值的元素 78 elementData[size++] = object; 79 } 80 81 82 /** 83 * 获取索引位置的值 84 * 85 * @param index 数组的索引 86 * @return 对应位置的索引值 87 */ 88 public Object getElementData(int index) { 89 return elementData[index]; 90 } 91 92 /** 93 * 设置元素 94 * 95 * @param object 设置的元素 96 * @param index 索引位置 97 */ 98 public void setElementData(Object object, int index) { 99 elementData[index] = object; 100 } 101 102 /** 103 * 重写toString方法,打印数组元素 104 * 105 * @return 数组元素样式 106 */ 107 @Override 108 public String toString() { 109 110 // 处理返回结果产生多个的状况 111 if (null != stringBuilder) { 112 stringBuilder = new StringBuilder(); 113 } 114 115 getStringBuilderResult(); 116 117 return stringBuilder.toString(); 118 } 119 120 /** 121 * 获取拼接结果集 122 */ 123 private void getStringBuilderResult() { 124 stringBuilder.append("MySelfArrayList : {"); 125 stringBuilder.append("elementData="); 126 127 for (int i = 0; i < size; i++) { 128 stringBuilder.append(elementData[i] + ","); 129 } 130 131 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 132 133 stringBuilder.append("}"); 134 } 135 }
4、升级Object的get和set方法为泛型
1 /* 2 * 获取索引位置的值 3 @param index 数组的索引 4 @return 对应位置的索引值 5 */ 6 public ME getElementData(int index) { return (ME)elementData[index]; } 7 8 /** 9 * 设置元素 10 * 11 * @param object 设置的元素 12 * @param index 索引位置 13 */ 14 public void setElementData(ME object, int index) { 15 elementData[index] = object; 16 }
测试
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("5"); 6 mySelfArrayList.add("6"); 7 mySelfArrayList.add("7"); 8 System.out.println("原数组:" + mySelfArrayList.toString()); 9 10 mySelfArrayList.setElementData("6", 2); 11 12 13 System.out.println("使用set()设置后数组:" + mySelfArrayList.toString()); 14 15 System.out.println("使用get()获取元素:" + mySelfArrayList.getElementData(1)); 16 17 18 }
5、添加判断索引的大小是否超过数组的大小判断
1 /** 自定义ArrayList,添加判断索引的大小是否超过数组的大小判断 / public class MySelfArrayList<ME> { 2 3 /** 4 * 存放元素的数组 5 */ 6 private Object[] elementData; 7 8 /** 9 * 存放数组的索引 10 */ 11 private int size; 12 13 14 /** 15 * 默认初始化Object数据的大小,参数是默认容量 16 */ 17 private static final int DEFAULT_CAPACITY = 10; 18 19 /** 20 * 封装toString方法返回结果值(自定义,未在源码中) 21 */ 22 StringBuilder stringBuilder; 23 24 25 /** 26 * <p>无参构造函数<p/> 27 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 28 * <p>或者是读取文件的方式在构造函数中存放<p/> 29 * <p>或者是常量的初始化<p/> 30 */ 31 public MySelfArrayList() { 32 33 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 34 elementData = new Object[DEFAULT_CAPACITY]; 35 36 // 封装toString方法返回结果值 37 stringBuilder = new StringBuilder(); 38 39 } 40 41 /** 42 * 有参构造函数 43 * 44 * @param capacity 传入容量,即你想要创建一个多大的数组 45 */ 46 public MySelfArrayList(int capacity) { 47 48 // 封装toString方法返回结果值 49 stringBuilder = new StringBuilder(); 50 51 if (capacity > 0) { 52 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 53 elementData = new Object[capacity]; 54 } else if (capacity == 0) { 55 // 当你new这个对象的时候,就会建立一个默认值大小的数组 56 elementData = new Object[DEFAULT_CAPACITY]; 57 } else { 58 throw new IllegalArgumentException("传入索引不合法: " + 59 capacity); 60 } 61 } 62 63 64 /** 65 * 数组添加元素方法 66 * 67 * @param object 任意类型的数据添加到数组中 68 */ 69 public void add(Object object) { 70 71 // 当传入的元素个数跟默认或自定义的长度相等的时候采用扩容机制 72 if (size == elementData.length) { 73 74 //定义一个更大的数组 75 Object[] newArray = new Object[elementData.length + (elementData.length >> 1)]; 76 77 // 拷贝旧的数组到新的数组中 78 System.arraycopy(elementData, 0, newArray, 0, elementData.length); 79 80 // 将新数组结果赋值给创建的数组 81 elementData = newArray; 82 } 83 84 85 // 每次调用这个方法的时候,就像数组中添加索引值的元素 86 elementData[size++] = object; 87 } 88 89 90 /** 91 * 获取索引位置的值 92 * 93 * @param index 数组的索引 94 * @return 对应位置的索引值 95 */ 96 public ME getElementData(int index) { 97 checkIndexRange(index); 98 return (ME) elementData[index]; 99 } 100 101 /** 102 * 设置元素 103 * 104 * @param object 设置的元素 105 * @param index 索引位置 106 */ 107 public void setElementData(ME object, int index) { 108 checkIndexRange(index); 109 elementData[index] = object; 110 } 111 112 /** 113 * 传入的值是否在数组范围内 114 * 115 * @param index 传入的索引值 116 */ 117 public void checkIndexRange(int index) { 118 119 // 传入的长度不能是负数和大于数组长度的数 120 if (index < 0 || index > size - 1) { 121 throw new IllegalArgumentException("传入索引不合法: " + 122 index); 123 } 124 } 125 126 /** 127 * 重写toString方法,打印数组元素 128 * 129 * @return 数组元素样式 130 */ 131 @Override 132 public String toString() { 133 134 // 处理返回结果产生多个的状况 135 if (null != stringBuilder) { 136 stringBuilder = new StringBuilder(); 137 } 138 139 getStringBuilderResult(); 140 141 return stringBuilder.toString(); 142 } 143 144 /** 145 * 获取拼接结果集 146 */ 147 private void getStringBuilderResult() { 148 stringBuilder.append("MySelfArrayList : {"); 149 stringBuilder.append("elementData="); 150 151 for (int i = 0; i < size; i++) { 152 stringBuilder.append(elementData[i] + ","); 153 } 154 155 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 156 157 stringBuilder.append("}"); 158 } 159 }
测试
1.参数越界
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList2 = new MySelfArrayList<>(-9); 4 }
2.set()越界
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("5"); 6 mySelfArrayList.add("6"); 7 mySelfArrayList.add("7"); 8 System.out.println("原数组:" + mySelfArrayList.toString()); 9 10 mySelfArrayList.setElementData("6", -5); 11 12 }
3.get()越界
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("5"); 6 mySelfArrayList.add("6"); 7 mySelfArrayList.add("7"); 8 System.out.println("原数组:" + mySelfArrayList.toString()); 9 10 mySelfArrayList.getElementData( -5); 11 12 }
6、添加remove方法
核心思想
也是拷贝,从被删除的元素之后的一个位置把元素拷贝进数组
核心代码
1 /* 2 * 指定位置移除元素 3 *@param index 传入的索引值 4 * 5 / 6 public void remove(int index) { checkIndexRange(index); 7 8 // 移动索引之后元素的长度 9 int numMovedLength = size - index - 1; 10 11 // 长度大于零,说明最后一个元素之后还有元素 12 if (numMovedLength > 0) { 13 System.arraycopy(elementData, index + 1, elementData, index, 14 numMovedLength); 15 } 16 17 // clear to let GC do its work 18 elementData[--size] = null; 19 20 } 21 22 23 /** 24 * 移除元素 25 * 26 * @param element 需要移除的元素 27 */ 28 public void remove(ME element) { 29 30 // 遍历元素组,找到与输入的元素相同的那个 31 for (int i = 0; i < size; i++) { 32 33 // 所有容器中比较操作,都是用equals,而不是'==' 34 if (element.equals(getElementData(i))) { 35 36 // 获得相同的元素的索引,通过索引进行移除操作 37 remove(i); 38 } 39 } 40 }
完整代码
1 /** 自定义ArrayList,添加移除操作 / 2 public class MySelfArrayList<ME> { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 49 // 封装toString方法返回结果值 50 stringBuilder = new StringBuilder(); 51 52 if (capacity > 0) { 53 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 54 elementData = new Object[capacity]; 55 } else if (capacity == 0) { 56 // 当你new这个对象的时候,就会建立一个默认值大小的数组 57 elementData = new Object[DEFAULT_CAPACITY]; 58 } else { 59 throw new IllegalArgumentException("传入索引不合法: " + 60 capacity); 61 } 62 } 63 64 65 /** 66 * 数组添加元素方法 67 * 68 * @param object 任意类型的数据添加到数组中 69 */ 70 public void add(Object object) { 71 72 // 当传入的元素个数跟默认或自定义的长度相等的时候采用扩容机制 73 if (size == elementData.length) { 74 75 //定义一个更大的数组 76 Object[] newArray = new Object[elementData.length + (elementData.length >> 1)]; 77 78 // 拷贝旧的数组到新的数组中 79 System.arraycopy(elementData, 0, newArray, 0, elementData.length); 80 81 // 将新数组结果赋值给创建的数组 82 elementData = newArray; 83 } 84 85 86 // 每次调用这个方法的时候,就像数组中添加索引值的元素 87 elementData[size++] = object; 88 } 89 90 91 /** 92 * 获取索引位置的值 93 * 94 * @param index 数组的索引 95 * @return 对应位置的索引值 96 */ 97 public ME getElementData(int index) { 98 checkIndexRange(index); 99 return (ME) elementData[index]; 100 } 101 102 /** 103 * 设置元素 104 * 105 * @param object 设置的元素 106 * @param index 索引位置 107 */ 108 public void setElementData(ME object, int index) { 109 checkIndexRange(index); 110 elementData[index] = object; 111 } 112 113 114 /** 115 * 指定位置移除元素 116 * 117 * @param index 传入的索引值 118 */ 119 public void remove(int index) { 120 checkIndexRange(index); 121 122 // 移动索引之后元素的长度 123 int numMovedLength = size - index - 1; 124 125 // 长度大于零,说明最后一个元素之后还有元素 126 if (numMovedLength > 0) { 127 System.arraycopy(elementData, index + 1, elementData, index, 128 numMovedLength); 129 } 130 131 // clear to let GC do its work 132 elementData[--size] = null; 133 134 } 135 136 137 /** 138 * 移除元素 139 * 140 * @param element 需要移除的元素 141 */ 142 public void remove(ME element) { 143 144 // 遍历元素组,找到与输入的元素相同的那个 145 for (int i = 0; i < size; i++) { 146 147 // 所有容器中比较操作,都是用equals,而不是'==' 148 if (element.equals(getElementData(i))) { 149 150 // 获得相同的元素的索引,通过索引进行移除操作 151 remove(i); 152 } 153 } 154 } 155 156 157 /** 158 * 传入的值是否在数组范围内 159 * 160 * @param index 传入的索引值 161 */ 162 public void checkIndexRange(int index) { 163 164 // 传入的长度不能是负数和大于数组长度的数 165 if (index < 0 || index > size - 1) { 166 throw new IllegalArgumentException("传入索引不合法: " + 167 index); 168 } 169 } 170 171 /** 172 * 重写toString方法,打印数组元素 173 * 174 * @return 数组元素样式 175 */ 176 @Override 177 public String toString() { 178 179 // 处理返回结果产生多个的状况 180 if (null != stringBuilder) { 181 stringBuilder = new StringBuilder(); 182 } 183 184 getStringBuilderResult(); 185 186 return stringBuilder.toString(); 187 } 188 189 /** 190 * 获取拼接结果集 191 */ 192 private void getStringBuilderResult() { 193 stringBuilder.append("MySelfArrayList : {"); 194 stringBuilder.append("elementData="); 195 196 for (int i = 0; i < size; i++) { 197 stringBuilder.append(elementData[i] + ","); 198 } 199 200 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 201 202 stringBuilder.append("}"); 203 } 204 }
测试
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("5"); 6 mySelfArrayList.add("6"); 7 mySelfArrayList.add("7"); 8 System.out.println("原数组:" + mySelfArrayList.toString()); 9 10 mySelfArrayList.remove(0); 11 12 mySelfArrayList.remove("6"); 13 14 System.out.println("移除后:" + mySelfArrayList.toString()); 15 16 }
7、添加其他方法
编辑源码
1 /** 自定义ArrayList,添加其他操作 / 2 public class MySelfArrayList<ME> { 3 4 /** 5 * 存放元素的数组 6 */ 7 private Object[] elementData; 8 9 /** 10 * 存放数组的索引 11 */ 12 private int size; 13 14 15 /** 16 * 默认初始化Object数据的大小,参数是默认容量 17 */ 18 private static final int DEFAULT_CAPACITY = 10; 19 20 /** 21 * 封装toString方法返回结果值(自定义,未在源码中) 22 */ 23 StringBuilder stringBuilder; 24 25 26 /** 27 * <p>无参构造函数<p/> 28 * <p>企业级开发一般会在构造函数对对象中存在的对象初始化<p/> 29 * <p>或者是读取文件的方式在构造函数中存放<p/> 30 * <p>或者是常量的初始化<p/> 31 */ 32 public MySelfArrayList() { 33 34 // 当你new 这个对象的时候,就会建立一个大小为10的Object数组 35 elementData = new Object[DEFAULT_CAPACITY]; 36 37 // 封装toString方法返回结果值 38 stringBuilder = new StringBuilder(); 39 40 } 41 42 /** 43 * 有参构造函数 44 * 45 * @param capacity 传入容量,即你想要创建一个多大的数组 46 */ 47 public MySelfArrayList(int capacity) { 48 49 // 封装toString方法返回结果值 50 stringBuilder = new StringBuilder(); 51 52 if (capacity > 0) { 53 // 当你new这个对象的时候,就会建立一个自定义大小的Object数组 54 elementData = new Object[capacity]; 55 } else if (capacity == 0) { 56 // 当你new这个对象的时候,就会建立一个默认值大小的数组 57 elementData = new Object[DEFAULT_CAPACITY]; 58 } else { 59 throw new IllegalArgumentException("传入索引不合法: " + 60 capacity); 61 } 62 } 63 64 65 /** 66 * 数组添加元素方法 67 * 68 * @param object 任意类型的数据添加到数组中 69 */ 70 public void add(Object object) { 71 72 // 当传入的元素个数跟默认或自定义的长度相等的时候采用扩容机制 73 if (size == elementData.length) { 74 75 //定义一个更大的数组 76 Object[] newArray = new Object[elementData.length + (elementData.length >> 1)]; 77 78 // 拷贝旧的数组到新的数组中 79 System.arraycopy(elementData, 0, newArray, 0, elementData.length); 80 81 // 将新数组结果赋值给创建的数组 82 elementData = newArray; 83 } 84 85 86 // 每次调用这个方法的时候,就像数组中添加索引值的元素 87 elementData[size++] = object; 88 } 89 90 91 /** 92 * 获取索引位置的值 93 * 94 * @param index 数组的索引 95 * @return 对应位置的索引值 96 */ 97 public ME getElementData(int index) { 98 checkIndexRange(index); 99 return (ME) elementData[index]; 100 } 101 102 /** 103 * 设置元素 104 * 105 * @param object 设置的元素 106 * @param index 索引位置 107 */ 108 public void setElementData(ME object, int index) { 109 checkIndexRange(index); 110 elementData[index] = object; 111 } 112 113 114 /** 115 * 指定位置移除元素 116 * 117 * @param index 传入的索引值 118 */ 119 public void remove(int index) { 120 checkIndexRange(index); 121 122 // 移动索引之后元素的长度 123 int numMovedLength = size - index - 1; 124 125 // 长度大于零,说明最后一个元素之后还有元素 126 if (numMovedLength > 0) { 127 System.arraycopy(elementData, index + 1, elementData, index, 128 numMovedLength); 129 } 130 131 // clear to let GC do its work 132 elementData[--size] = null; 133 134 } 135 136 137 /** 138 * 移除元素 139 * 140 * @param element 需要移除的元素 141 */ 142 public void remove(ME element) { 143 144 // 遍历元素组,找到与输入的元素相同的那个 145 for (int i = 0; i < size; i++) { 146 147 // 所有容器中比较操作,都是用equals,而不是'==' 148 if (element.equals(getElementData(i))) { 149 150 // 获得相同的元素的索引,通过索引进行移除操作 151 remove(i); 152 } 153 } 154 } 155 156 157 /** 158 * 数组大小 159 * 160 * @return 数组大小的值 161 */ 162 public int size() { 163 return size; 164 } 165 166 /** 167 * 判断数组是否为空 168 * 169 * @return 是 true 否 false 170 */ 171 public boolean isEmpty() { 172 return size == 0 ? true : false; 173 } 174 175 /** 176 * 传入的值是否在数组范围内 177 * 178 * @param index 传入的索引值 179 */ 180 public void checkIndexRange(int index) { 181 182 // 传入的长度不能是负数和大于数组长度的数 183 if (index < 0 || index > size - 1) { 184 throw new IllegalArgumentException("传入索引不合法: " + 185 index); 186 } 187 } 188 189 /** 190 * 重写toString方法,打印数组元素 191 * 192 * @return 数组元素样式 193 */ 194 @Override 195 public String toString() { 196 197 // 处理返回结果产生多个的状况 198 if (null != stringBuilder) { 199 stringBuilder = new StringBuilder(); 200 } 201 202 getStringBuilderResult(); 203 204 return stringBuilder.toString(); 205 } 206 207 /** 208 * 获取拼接结果集 209 */ 210 private void getStringBuilderResult() { 211 stringBuilder.append("MySelfArrayList : {"); 212 stringBuilder.append("elementData="); 213 214 for (int i = 0; i < size; i++) { 215 stringBuilder.append(elementData[i] + ","); 216 } 217 218 stringBuilder.setCharAt(stringBuilder.length() - 1, ']'); 219 220 stringBuilder.append("}"); 221 } 222 }
测试
1 public static void main(String[] args) { 2 3 MySelfArrayList<String> mySelfArrayList = new MySelfArrayList<>(); 4 5 mySelfArrayList.add("5"); 6 mySelfArrayList.add("6"); 7 mySelfArrayList.add("7"); 8 9 System.out.println("数组大小:" + mySelfArrayList.size()); 10 System.out.println("数组是否为空:" + mySelfArrayList.isEmpty()); 11 12 13 }