• ArrayList源码解析


    ArrayList源码解析

    ArrayList简介:

    ArrayList 是list接口的一个常用实现类。它的对象可以认为是一维数组的“类版本”。我们很快就可以看到,ArrayList 对象可以看做是一维数组的改良版本。类似于数组,ArrayList 对象支持元素的随机访问;也就是说,只要给出元素的索引,任何元素的访问时间都是常数。但是同数组不同的是,ArrayList 对象的大小在程序执行的过程中可以自动进行调整,并且ArrayList对象具有在任何索引位置插入和删除对象的方法,而数组如果想要插入和删除对象,则必须要编写代码增加和减少储存空间。

    ArrayList方法简介:

    首先我们先来看一下ArrayList的所有公共方法。

    注:下面方法除构造函数方法外,其他方法皆按照字母顺序排序。

     1 1、public Arraylist()
     2 2、public ArrayList(int initalCapacity)
     3 3、public ArrayList(Collection<? extends E> c)
     4 4、public boolean add(E e)
     5 5、public void add(int index, E element)
     6 6、 public boolean addAll(int index, Collection<? extends E> c)
     7 7、public boolean addAll(Collection<? extends E> c)
     8 8、 public void clear()
     9 9、 public Object clone()
    10 10、 public boolean contains(Object o)
    11 11、public boolean containsAll(Collection<?> c)
    12 12、public void ensureCapacity(int minCapacity)
    13 13、public boolean equals(Object o)
    14 14、 public void forEach(Consumer<? super E> action)
    15 15、public E get(int index)
    16 16、public int hashCode()
    17 17、 public int indexOf(Object o)
    18 18、public boolean isEmpty()
    19 19、public Iterator<E> iterator()
    20 20、public int lastIndexOf(Object o)
    21 21、public ListIterator<E> listIterator()
    22 22、public ListIterator<E> listIterator(int index)
    23 23、public E remove(int index)
    24 24、public boolean remove(Object o)
    25 25、public boolean removeAll(Collection<?> c)
    26 26、public boolean removeIf(Predicate<? super E> filter)
    27 27、 public void replaceAll(UnaryOperator<E> operator)
    28 28、public boolean retainAll(Collection<?> c)
    29 29、public E set(int index, E element)
    30 30、public int size()
    31 31、public void sort(Comparator<? super E> c)
    32 32、public Spliterator<E> spliterator()
    33 33、public List<E> subList(int fromIndex, int toIndex)
    34 34、public Object[] toArray()
    35 35、public <T> T[] toArray(T[] a)
    36 36、public String toString()
    37 37、public void trimToSize()
    View Code

    ArrayList方法解析:

    ArrayList类结构关系:

    在具体分析Arrayl类的方法之前,我们先看一下ArrayList类的继承关系。
     
    从图中可以看出,ArrayList继承AbstractList类,并且实现了List、RandomAccess、Serializable接口。
    其中RandomAccess接口为一个空接口,起到一个标识的作用,如果集合类是RandomAccess的实现,则尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历,在效率上要差一些。反过来,如果List是Sequence List,则最好用迭代器来进行迭代。 其具体细节在我们在这里就不进行讨论了,感兴趣的同学可以自己去查一查。
    Serializable是启用序列化功能的接口,这里也不进行讨论了。
    AbstractList继承了AbstractCollection.两者都是抽象类,AbstractCollection提供了Collection接口的一些方法的默认实现,AbstractCollection提供了List接口
    的默认实现(个别方法为抽象方法)。

    ArrayList类的属性:

     1 //默认容量的大小
     2 private static final int DEFAULT_CAPACITY = 10;
     3 
     4 //空数组常量
     5 private static final Object[] EMPTY_ELEMENTDATA = {};
     6 
     7 //默认的空数组常量
     8 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
     9 
    10 //存放元素的数组,从这可以发现ArrayList的底层实现就是一个Object数组
    11 transient Object[] elementData;
    12 
    13 //数组中包含的元素个数
    14 private int size;
    15 
    16 //数组的最大上限
    17 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    View Code

    ArrayList的属性非常少,一共就只有这五个。其中:DEFAULT_CAPACITY 代表默认容量的大小,在后面我们可以看到,在像ArrayList对象第一次添
    加元素的时候,会将ArrayList的容量设置为默认的容量。EMPTY_ELEMENTDATE和DEFAULTCAPACITY_EMPTY_ELEMENTDATA区别不大。这个在后面
    讲构造器的时候会详细讲到。其中最重要的莫过于elementData了,ArrayList所有的方法都是建立在elementData之上。

    ArrayList构造函数:

    ArrayList一共有三个构造函数,分别为:

     1 public ArrayList(int initialCapacity) {
     2         if (initialCapacity > 0) {
     3             this.elementData = new Object[initialCapacity];
     4         } else if (initialCapacity == 0) {
     5             this.elementData = EMPTY_ELEMENTDATA;
     6         } else {
     7             throw new IllegalArgumentException("Illegal Capacity: "+
     8                                                initialCapacity);
     9         }
    10     }
    11     public ArrayList() {
    12         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    13     }
    14     public ArrayList(Collection<? extends E> c) {
    15         elementData = c.toArray();
    16         if ((size = elementData.length) != 0) {
    17             // c.toArray might (incorrectly) not return Object[] (see 6260652)
    18             if (elementData.getClass() != Object[].class)
    19                 elementData = Arrays.copyOf(elementData, size, Object[].class);
    20         } else {
    21             // replace with empty array.
    22             this.elementData = EMPTY_ELEMENTDATA;
    23         }
    24     }
    View Code
    从构造函数我们可以看出,elementDate默认是一个大小为0的的数组,即DEFAULTCAPACITY_EMPTY_ELEMENTDATA,而
    当指定数组长度时,elementData的初始大小就变成了我们所指定的初始大小了。如果我们指定数组的默认长度为0时,
    elementDate即为EMPTY_ELEMENTDATA,在这里我们还看不出两者的区别,在后面讲到add方法时,就可以看到两者的不同了。
    ArrayList同样可以传入一个Collection,当Collection不为空时,复制该Collection。否则elementDate仍然为EMPTY_ELEMENTDATA。

    ArrayList的公共方法:

    ArrayList的添加方法:

    ArrayList添加单个元素有两个方法,分别为:
     1     public boolean add(E e) {
     2         ensureCapacityInternal(size + 1);  // Increments modCount!!
     3         elementData[size++] = e;
     4         return true;
     5     }
     6     public void add(int index, E element) {
     7         rangeCheckForAdd(index);
     8 
     9         ensureCapacityInternal(size + 1);  // Increments modCount!!
    10         System.arraycopy(elementData, index, elementData, index + 1,
    11                          size - index);
    12         elementData[index] = element;
    13         size++;
    14     }
    View Code

    add(E e)方法是用来添加一个单个的元素,其调用了私有方法enesureCapacityInternal(size+1).

     1   private void ensureCapacityInternal(int minCapacity) {
     2         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     3             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
     4         }
     5 
     6         ensureExplicitCapacity(minCapacity);
     7     }
     8     private void ensureExplicitCapacity(int minCapacity) {
     9         modCount++;//
    10         // overflow-conscious code
    11         if (minCapacity - elementData.length > 0)
    12             grow(minCapacity);
    13     }
    14  private void grow(int minCapacity) {
    15         // overflow-conscious code
    16         int oldCapacity = elementData.length;
    17         int newCapacity = oldCapacity + (oldCapacity >> 1);
    18         if (newCapacity - minCapacity < 0)
    19             newCapacity = minCapacity;
    20         if (newCapacity - MAX_ARRAY_SIZE > 0)
    21             newCapacity = hugeCapacity(minCapacity);
    22         // minCapacity is usually close to size, so this is a win:
    23         elementData = Arrays.copyOf(elementData, newCapacity);
    24     }
    我们可以看到,在这个方法中,增加了一个判断,elementData ==DEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么minCapacity=DEFAULT_CAPACITY,也就是等于10.这就区分出了前面所说的DEFAULTCAPACITY_EMPTY_ELEMENTDATA和EMPTY_ELEMENTDATA的区别。当elemetnDate=DEFAULT_CAPACITY时,第一次添加元素时,容量变为1,而当elementData =DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,第一次添加元素时,容量变为10.
    同时,我们也可以看出ArrayList在面对容量不足时,每次扩容都是在原容量的基础上,增加0.5倍。
    而add(int index,E e)就比较好理解了,先检查index,然后判断是否需要扩容,需要就扩容,然后将原来的elemetnDate从index起始到最后复制到index+1的位置上,然后在原index位置添加元素。

     ArrayList添加多个元素的方法一样有两个,分别为:

     1     public boolean addAll(Collection<? extends E> c) {
     2         Object[] a = c.toArray();
     3         int numNew = a.length;
     4         ensureCapacityInternal(size + numNew);  // Increments modCount
     5         System.arraycopy(a, 0, elementData, size, numNew);
     6         size += numNew;
     7         return numNew != 0;
     8     }
     9 
    10  public boolean addAll(int index, Collection<? extends E> c) {
    11         rangeCheckForAdd(index);
    12 
    13         Object[] a = c.toArray();
    14         int numNew = a.length;
    15         ensureCapacityInternal(size + numNew);  // Increments modCount
    16 
    17         int numMoved = size - index;
    18         if (numMoved > 0)
    19             System.arraycopy(elementData, index, elementData, index + numNew,
    20                              numMoved);
    21 
    22         System.arraycopy(a, 0, elementData, index, numNew);
    23         size += numNew;
    24         return numNew != 0;
    25     }

    插入多个元素,与插入单个元素的逻辑是一样的,在这里就不再重复了。

    ArrayList删除元素方法:

    ArrayList删除元素的方法一共有五个,分别是

     1   public E remove(int index) {
     2         rangeCheck(index);
     3 
     4         modCount++;
     5         E oldValue = elementData(index);
     6 
     7         int numMoved = size - index - 1;
     8         if (numMoved > 0)
     9             System.arraycopy(elementData, index+1, elementData, index,
    10                              numMoved);
    11         elementData[--size] = null; // clear to let GC do its work
    12 
    13         return oldValue;
    14     }

    remove(int index)的处理逻辑:先检查index是否大于elementDate的size,如果大于的话,则抛出异常;然后获取elementDate[index],留在方法结束后返回;然后复制素组,从index+1开始,复制size-index-1个元素,复制到elementDate,从index开始;最后设置elementDate[--size]=null;

     1     public boolean remove(Object o) {
     2         if (o == null) {
     3             for (int index = 0; index < size; index++)
     4                 if (elementData[index] == null) {
     5                     fastRemove(index);
     6                     return true;
     7                 }
     8         } else {
     9             for (int index = 0; index < size; index++)
    10                 if (o.equals(elementData[index])) {
    11                     fastRemove(index);
    12                     return true;
    13                 }
    14         }
    15         return false;
    16     }

    remove(Object o)的逻辑:先判断Object 是否为null,如果为null,则遍历ArrayList,删除所有的null值,如果有值被删除,则返回true;如果Object不为null,同样遍历ArrayList,删除ArrayList中相同的元素,如果有元素被删除,则返回true.

    而fastRemove(int index)的逻辑与remove(int index),完全一致,只是少了对index的验证。

    1  public boolean removeAll(Collection<?> c) {
    2         Objects.requireNonNull(c);
    3         return batchRemove(c, false);
    4     }
     1  private boolean batchRemove(Collection<?> c, boolean complement) {
     2         final Object[] elementData = this.elementData;
     3         int r = 0, w = 0;
     4         boolean modified = false;
     5         try {
     6             for (; r < size; r++)
     7                 if (c.contains(elementData[r]) == complement)
     8                     elementData[w++] = elementData[r];
     9         } finally {
    10             // Preserve behavioral compatibility with AbstractCollection,
    11             // even if c.contains() throws.
    12             if (r != size) {
    13                 System.arraycopy(elementData, r,
    14                                  elementData, w,
    15                                  size - r);
    16                 w += size - r;
    17             }
    18             if (w != size) {
    19                 // clear to let GC do its work
    20                 for (int i = w; i < size; i++)
    21                     elementData[i] = null;
    22                 modCount += size - w;
    23                 size = w;
    24                 modified = true;
    25             }
    26         }
    27         return modified;
    28     }

    从上面的代码我们可以看出,remove(Collection<?> c)的逻辑:先判断c是否为null,如果为null,则抛出异常。然后遍历elementDate,如果c包含数组elementDate中的元素

    ,则将该元素添加一次替换原elementDate数组中,最后,将数组的其余位置设为null,如果新数组比原来数组中的元素少,则已经删除了元素,返回true.

    除此之外,还有一个清空ArrayList的方法
    1     public void clear() {
    2         modCount++;
    3 
    4         // clear to let GC do its work
    5         for (int i = 0; i < size; i++)
    6             elementData[i] = null;
    7 
    8         size = 0;
    9     }

    clear()方法的逻辑:遍历,删除所有元素。

    除此之外,还有一个retainAll(collenction<T> c)方法,该方法愿意是取得两个集合得交集,在这里也可以理解为删除集合中不与collection c 重复得元素。

     1 return batchRemove(c, true); 

    可以看到,它得处理逻辑和removeAll是同样得逻辑,这里就不再重复了。

    ArrayList修改元素的方法

    在JDK1.8之前,修改元素只有一个方法,就是set(int index,Object c).

    1  public E set(int index, E element) {
    2         rangeCheck(index);
    3 
    4         E oldValue = elementData(index);
    5         elementData[index] = element;
    6         return oldValue;
    7     }

    逻辑很简单,就是先检查index,然后新元素替换旧元素,并返回旧元素。

    在JDK1.8中,添加了一个新方法,批量修改replaceAll(UnaryOperator<E> operator):

     1 public void replaceAll(UnaryOperator<E> operator) {
     2         Objects.requireNonNull(operator);
     3         final int expectedModCount = modCount;
     4         final int size = this.size;
     5         for (int i=0; modCount == expectedModCount && i < size; i++) {
     6             elementData[i] = operator.apply((E) elementData[i]);
     7         }
     8         if (modCount != expectedModCount) {
     9             throw new ConcurrentModificationException();
    10         }
    11         modCount++;
    12     }

     UnaryOperator<T> extends Function<T, T>,而Function<T,R>方法中有一个抽象方法,R apply<T,t>,方法的原意应该是将一个T转换成R.而这里使用,UnaryOperator,则只能将T转换成T。我们在使用ReplaceAll方法是,必须重写apply方法,作为转换规则。例如:

     1 public class ArrayListTest {
     2     public static void main(String[] args) {
     3         List<String> list = new ArrayList<String>();
     4         list.add("科比");
     5         list.add("詹姆斯");
     6         list.add("库里");
     7         list.replaceAll(new UnaryOperator<String>() {
     8             @Override
     9             public String apply(String t) {
    10                 // TODO Auto-generated method stub
    11                 return t+"牛逼";
    12             }
    13         });
    14         System.out.println(list);
    15     }
    16 }
    输出的结果为:
    [科比牛逼, 詹姆斯牛逼, 库里牛逼]

    ArrayList查找元素得方法:

       

    1    public E get(int index) {
    2         rangeCheck(index);
    3 
    4         return elementData(index);
    5     }

    get(int index)方法,通过元素的下标来获取元素。其原理就是获取数组的当前下表的元素。

     1     public int indexOf(Object o) {
     2         if (o == null) {
     3             for (int i = 0; i < size; i++)
     4                 if (elementData[i]==null)
     5                     return i;
     6         } else {
     7             for (int i = 0; i < size; i++)
     8                 if (o.equals(elementData[i]))
     9                     return i;
    10         }
    11         return -1;
    12     }

     indextOf(Object o),查找ArrayList是否含有某元素,且返回该元素在集合中的第一个位置的下标。通过遍历元素,获取该集合所含有的第一个该元素的下标。如果不含有该元素,则返回-1.

     1     public int lastIndexOf(Object o) {
     2         if (o == null) {
     3             for (int i = size-1; i >= 0; i--)
     4                 if (elementData[i]==null)
     5                     return i;
     6         } else {
     7             for (int i = size-1; i >= 0; i--)
     8                 if (o.equals(elementData[i]))
     9                     return i;
    10         }
    11         return -1;
    12     }

    lastIndexOf(Object o),与indexOf方法想法,该方法查找该元素在集合中最后一个位置,并返回下标。其逻辑与indexOf基本一致,只不过是在遍历的时候选择从后往前遍历。

     1 public boolean isEmpty() { 2 return size == 0; 3 } 

    isEmpth()方法用来查看集合是否为空集合。如果size=0,则为空集合,返回true。否则返回false。

      public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    

     contains(Object o)查看集合中是否含有某元素。其调用indexOf(Object o),如果含有返回ture,否则返回false.

       public int size() {
            return size;
        }
    

     size()方法用来查看集合中含有多少个元素,返回元素个数。

    ArrayList的一些其他常用方法:

     1    public Object clone() {
     2         try {
     3             ArrayList<?> v = (ArrayList<?>) super.clone();
     4             v.elementData = Arrays.copyOf(elementData, size);
     5             v.modCount = 0;
     6             return v;
     7         } catch (CloneNotSupportedException e) {
     8             // this shouldn't happen, since we are Cloneable
     9             throw new InternalError(e);
    10         }
    11     }

    clone()方法,用来复制集合并返回一个新的集合。而查看copyOf源码,发现最底层是使用native方法进行的复制。我无法确定其到底是深复制还是浅复制。

      private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException; 

    所以我写了一个简单的测试代码,代码如下:

     1 public class ArrayListTest{
     2     public static void main(String[] args) {
     3         ArrayList<User> list = new ArrayList<User>();
     4         list.add(new User("科比"));
     5         list.add(new User("詹姆斯"));
     6         list.add(new User("库里"));
     7         ArrayList list1= (ArrayList) list.clone();
     8         User user = list.get(1);
     9         user.name = "麦迪";
    10         System.out.println(list1);
    11     }
    12 }
    13 
    14 class User{
    15      String name;
    16     public User(String name){
    17         this.name = name;
    18     }
    19     @Override
    20     public String toString() {
    21         return name;
    22     }
    23 }

    打印结果为:

    [科比, 麦迪, 库里]
    

      说明ArrayList的复制为潜复制,因为其数组中的元素,并没有进行值复制,而是直接复制了元素的引用。

    在Java8中,ArrayList添加了一种新的遍历方法。foreach+lambda表达式遍历。代码如下:

    1 public class ArrayListTest{
    2     public static void main(String[] args) {
    3         ArrayList<String> list = new ArrayList<String>();
    4         list.add("科比");
    5         list.add("詹姆斯");
    6         list.add("库里");
    7         list.forEach((s)->System.out.println(s));
    8     }
    9 }

    因为不懂lambda表达式的实现原理,foreach的源码实在看不懂。等以后研究了lambda表达式的实现原理,在回来研究下foreach方法。

     在Java8中,ArrayList同样新添加了一种排序方法。sort(Comparator<? super E> c).源码如下:

     1  @Override
     2     @SuppressWarnings("unchecked")
     3     public void sort(Comparator<? super E> c) {
     4         final int expectedModCount = modCount;
     5         Arrays.sort((E[]) elementData, 0, size, c);
     6         if (modCount != expectedModCount) {
     7             throw new ConcurrentModificationException();
     8         }
     9         modCount++;
    10     }

    发现,ArrayList的排序,其实就是调用了数组的排序。我们继续往下看,数组是如何排序的:

     1     public static <T> void sort(T[] a, int fromIndex, int toIndex,
     2                                 Comparator<? super T> c) {
     3         if (c == null) {
     4             sort(a, fromIndex, toIndex);
     5         } else {
     6             rangeCheck(a.length, fromIndex, toIndex);
     7             if (LegacyMergeSort.userRequested)
     8                 legacyMergeSort(a, fromIndex, toIndex, c);
     9             else
    10                 TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
    11         }
    12     }
    1     public static void sort(Object[] a, int fromIndex, int toIndex) {
    2         rangeCheck(a.length, fromIndex, toIndex);
    3         if (LegacyMergeSort.userRequested)
    4             legacyMergeSort(a, fromIndex, toIndex);
    5         else
    6             ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
    7     }
    1  private static void legacyMergeSort(Object[] a,
    2                                         int fromIndex, int toIndex) {
    3         Object[] aux = copyOfRange(a, fromIndex, toIndex);
    4         mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
    5     }
     1 @SuppressWarnings({"unchecked", "rawtypes"})
     2     private static void mergeSort(Object[] src,
     3                                   Object[] dest,
     4                                   int low,
     5                                   int high,
     6                                   int off) {
     7         int length = high - low;
     8 
     9         // Insertion sort on smallest arrays
    10         if (length < INSERTIONSORT_THRESHOLD) {
    11             for (int i=low; i<high; i++)
    12                 for (int j=i; j>low &&
    13                          ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
    14                     swap(dest, j, j-1);
    15             return;
    16         }
    17 
    18         // Recursively sort halves of dest into src
    19         int destLow  = low;
    20         int destHigh = high;
    21         low  += off;
    22         high += off;
    23         int mid = (low + high) >>> 1;
    24         mergeSort(dest, src, low, mid, -off);
    25         mergeSort(dest, src, mid, high, -off);
    26 
    27         // If list is already sorted, just copy from src to dest.  This is an
    28         // optimization that results in faster sorts for nearly ordered lists.
    29         if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
    30             System.arraycopy(src, low, dest, destLow, length);
    31             return;
    32         }
    33 
    34         // Merge sorted halves (now in src) into dest
    35         for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
    36             if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
    37                 dest[i] = src[p++];
    38             else
    39                 dest[i] = src[q++];
    40         }
    41     }
    1    /** To be removed in a future release. */
    2     private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
    3                                             Comparator<? super T> c) {
    4         T[] aux = copyOfRange(a, fromIndex, toIndex);
    5         if (c==null)
    6             mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
    7         else
    8             mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
    9     }
     1    @SuppressWarnings({"rawtypes", "unchecked"})
     2     private static void mergeSort(Object[] src,
     3                                   Object[] dest,
     4                                   int low, int high, int off,
     5                                   Comparator c) {
     6         int length = high - low;
     7 
     8         // Insertion sort on smallest arrays
     9         if (length < INSERTIONSORT_THRESHOLD) {
    10             for (int i=low; i<high; i++)
    11                 for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
    12                     swap(dest, j, j-1);
    13             return;
    14         }
    15 
    16         // Recursively sort halves of dest into src
    17         int destLow  = low;
    18         int destHigh = high;
    19         low  += off;
    20         high += off;
    21         int mid = (low + high) >>> 1;
    22         mergeSort(dest, src, low, mid, -off, c);
    23         mergeSort(dest, src, mid, high, -off, c);
    24 
    25         // If list is already sorted, just copy from src to dest.  This is an
    26         // optimization that results in faster sorts for nearly ordered lists.
    27         if (c.compare(src[mid-1], src[mid]) <= 0) {
    28            System.arraycopy(src, low, dest, destLow, length);
    29            return;
    30         }
    31 
    32         // Merge sorted halves (now in src) into dest
    33         for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
    34             if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
    35                 dest[i] = src[p++];
    36             else
    37                 dest[i] = src[q++];
    38         }
    39     }

    可以看出,当比较器为空时,调用了mergeSort(Object[] src,Object[] dest,int low, int high, int off方法,不为空时,调用了mergeSort(Object[] src,Object[] dest,int low, int high, int off,Comparator c方法,两个方法基本一模一样,唯一的区别就是在有默认比较器的时候,两个元素的比较实用默认比较器的比较方法来比较。

    仔细看两个方法,可以看出,ArrayList.sort方法 时间上是使用了一种优化过后的递归排序,在数组长度小于7的时候使用直接插入排序。数组长度大于7的时候,使用归并排序,直至子数组的长度小于7.

    归并排序详见我的另一篇随笔经典排序算法--归并排序

    写在最后:
      此篇随笔仅用来记录我的学习内容,如有错误,欢迎指正。谢谢!!!
  • 相关阅读:
    iOS开发时,在Xcode中添加多个Targets进行版本控制
    如何给苹果公司发邮件?
    快快快!27个提升效率的iOS开源库推荐
    史上最全的常用iOS的第三方框架
    Ajax提交与传统表单提交的区别说明
    js原生ajax请求get post笔记
    查看iOS Crash logs
    如何提高iOS开发能力
    iOS 常用的#define合集
    Xcode编译错误和警告汇总
  • 原文地址:https://www.cnblogs.com/xsyfl/p/6842946.html
Copyright © 2020-2023  润新知