JDK源码阅读-------自学笔记(二十二)(java.util.ArrayList自定义晋级,ArrayList实战详解)


  • 简介(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  * 

    无参构造函数

    28 *

    企业级开发一般会在构造函数对对象中存在的对象初始化

    29 *

    或者是读取文件的方式在构造函数中存放

    30 *

    或者是常量的初始化

    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
      需要理解数组的概念,详见:

  • 进阶篇(Advanced)

         1、添加自定义泛型

             建立源码

 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  * 

无参构造函数

28 *

企业级开发一般会在构造函数对对象中存在的对象初始化

29 *

或者是读取文件的方式在构造函数中存放

30 *

或者是常量的初始化

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 
11 
12 }

        2、添加扩容机制

            扩容机制:通过定义新的更大的数组,将旧数组中的内容拷贝到新数组,来实现扩容

            两个核心问题:
                什么时候扩容?
                   当默认数组或自定义数组的最大值无法承载添加的元素数量的时候,进行扩容.比如:默认是10,添加第11个元素,就会报错,所以此时就要修改代码,以便适应更多情况.
                怎么扩容?
                  (1)定义一个更大的数组,比如建立一个二倍大小的数组,为了提高效率,可以采用左移的方式,左移一位<<1.源码中是原长度+原长度的一半,即如果是原长度10,扩容后就是15. 
                  (2)使用拷贝机制,将原来的数组拷贝到新数组.
                  拷贝机制详见:

           建立源码

  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  * 

无参构造函数

28 *

企业级开发一般会在构造函数对对象中存在的对象初始化

29 *

或者是读取文件的方式在构造函数中存放

30 *

或者是常量的初始化

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 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 {
  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  * 

无参构造函数

28 *

企业级开发一般会在构造函数对对象中存在的对象初始化

29 *

或者是读取文件的方式在构造函数中存放

30 *

或者是常量的初始化

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 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 {
  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  * 

无参构造函数

27 *

企业级开发一般会在构造函数对对象中存在的对象初始化

28 *

或者是读取文件的方式在构造函数中存放

29 *

或者是常量的初始化

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 mySelfArrayList2 = new MySelfArrayList<>(-9);
4 }

         2.set()越界

 1 public static void main(String[] args) {
 2 
 3     MySelfArrayList 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 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 {
  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  * 

无参构造函数

28 *

企业级开发一般会在构造函数对对象中存在的对象初始化

29 *

或者是读取文件的方式在构造函数中存放

30 *

或者是常量的初始化

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 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 {
  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  * 

无参构造函数

28 *

企业级开发一般会在构造函数对对象中存在的对象初始化

29 *

或者是读取文件的方式在构造函数中存放

30 *

或者是常量的初始化

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