zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Navicat Premium15安装与激活
    JDK13.0.1安装与环境变量的配置(Win10平台为例)
    Linux系统手动安装Firefox浏览器
    Debian 9.5 解决中文显示乱码
    debian 安装后需做的几件事
    Windows10 Linux子系统安装图形化界面的两种方法及其对比
    线程池大小设置,CPU的核心数、线程数的关系和区别,同步与堵塞完全是两码事
    Java学习笔记八(反射)
    高速排序法(一)
    Java深入
  • 原文地址:https://www.cnblogs.com/liuyangfirst/p/12953743.html
Copyright © 2011-2022 走看看