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  * <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 }
    View Code

    测试简单实体类

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

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

            测试

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

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

           测试

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

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

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

          测试

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

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

      测试

         1.参数越界

1 public static void main(String[] args) {
2 
3     MySelfArrayList<String> mySelfArrayList2 = new MySelfArrayList<>(-9);
4 }
View Code

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

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

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

       完整代码

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

      测试

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

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

       测试

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

猜你喜欢

转载自www.cnblogs.com/liuyangfirst/p/12953743.html