【Java源码分析】 工具类->数组

349 阅读3分钟

数组

数据结构的构成主要是有数组和链表构建。 数组侧重的内存的随机寻址,方便快速搜索和定位。链表主要是通过逻辑关联,便于逻辑结构映射到物理结构,适合新增,更新和删除操作。

随着项目做的越多,越发现底层的逻辑代码是是非常的完美,并且执行效率更高。 如果自己去实现,时间和复杂的都差很多。 那怎么利用好已有的SDK的方法能力,很考验对于源码的理解能力。

1. ArrayList

功能需求
  • 对于数组元素进行动态的管理
源码分析
  • 构造数组

    public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
    }
    
  • 申请数组空间,默认是10数组

    public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;
    
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
    }
    
  • 对于数组空间不够,采用复制数组的方法

    • 具体使用System.arraycopy 中的 Arrays.copyOf(elementData, newCapacity);
  • 数组的增删改成的操作

    • 增加

      public boolean add(E e) {
      ensureCapacityInternal(size + 1);  // Increments modCount!!
      elementData[size++] = e;
      return true;
      }
      
    • 删除

      public E remove(int index) {
        rangeCheck(index);
      
      modCount++;
      E oldValue = elementData(index);
      
      int numMoved = size - index - 1;
      if (numMoved > 0)
          System.arraycopy(elementData, index+1, elementData, index,
                           numMoved);
      elementData[--size] = null; // clear to let GC do its work
      
      return oldValue;
      }
      
    • 修改

      public E set(int index, E element) {
            rangeCheck(index);
      
      E oldValue = elementData(index);
      elementData[index] = element;
      return oldValue;
      }
      
    • 查询

      public E get(int index) {
          rangeCheck(index);
      return elementData(index);
      }
      
    • 排序

      public static <T> void sort(T[] a, int fromIndex, int toIndex,
                        Comparator<? super T> c) {
      if (c == null) {
      sort(a, fromIndex, toIndex);
      } else {
      rangeCheck(a.length, fromIndex, toIndex);
      if (LegacyMergeSort.userRequested)
          legacyMergeSort(a, fromIndex, toIndex, c);
      else
          TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
      }
      }
      
      • 数组采用二分法排序
        
      private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
                  this.a = a;
                  this.c = c;
      
          // Allocate temp storage (which may be increased later if necessary)
          int len = a.length;
          int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
              len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
          if (work == null || workLen < tlen || workBase + tlen > work.length) {
              @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
              T[] newArray = (T[])java.lang.reflect.Array.newInstance
                  (a.getClass().getComponentType(), tlen);
              tmp = newArray;
              tmpBase = 0;
              tmpLen = tlen;
          }
          else {
              tmp = work;
              tmpBase = workBase;
              tmpLen = workLen;
          }
      
          int stackLen = (len <    120  ?  5 :
                          len <   1542  ? 10 :
                          len < 119151  ? 24 : 49);
          runBase = new int[stackLen];
          runLen = new int[stackLen];
          }
      

2. Arrays 排序操作

功能需求
源码分析
  • 快速排序(DualPivotQuicksort)

    -  /**
    
     * Sorts the specified range of the array using the given
    
     * workspace array slice if possible for merging
       *
    
     * @param a the array to be sorted
    
     * @param left the index of the first element, inclusive, to be sorted
    
     * @param right the index of the last element, inclusive, to be sorted
    
     * @param work a workspace array (slice)
    
     * @param workBase origin of usable space in work array
    
     * @param workLen usable size of work array
       */
       static void sort(int[] a, int left, int right,
                    int[] work, int workBase, int workLen) {
       // Use Quicksort on small arrays
       if (right - left < QUICKSORT_THRESHOLD) {
           sort(a, left, right, true);
           return;
       }
    
       /*
    
        * Index run[i] is the start of i-th run
        * (ascending or descending sequence).
          */
          int[] run = new int[MAX_RUN_COUNT + 1];
          int count = 0; run[0] = left;
    
       // Check if the array is nearly sorted
       for (int k = left; k < right; run[count] = k) {
           if (a[k] < a[k + 1]) { // ascending
               while (++k <= right && a[k - 1] <= a[k]);
           } else if (a[k] > a[k + 1]) { // descending
               while (++k <= right && a[k - 1] >= a[k]);
               for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
                   int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
               }
           } else { // equal
               for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
                   if (--m == 0) {
                       sort(a, left, right, true);
                       return;
                   }
               }
           }
    
           /*
            * The array is not highly structured,
            * use Quicksort instead of merge sort.
            */
           if (++count == MAX_RUN_COUNT) {
               sort(a, left, right, true);
               return;
           }
    
       }
    
       // Check special cases
       // Implementation note: variable "right" is increased by 1.
       if (run[count] == right++) { // The last run contains one element
           run[++count] = right;
       } else if (count == 1) { // The array is already sorted
           return;
       }
    
       // Determine alternation base for merge
       byte odd = 0;
       for (int n = 1; (n <<= 1) < count; odd ^= 1);
    
       // Use or create temporary array b for merging
       int[] b;                 // temp array; alternates with a
       int ao, bo;              // array offsets from 'left'
       int blen = right - left; // space needed for b
       if (work == null || workLen < blen || workBase + blen > work.length) {
           work = new int[blen];
           workBase = 0;
       }
       if (odd == 0) {
           System.arraycopy(a, left, work, workBase, blen);
           b = a;
           bo = 0;
           a = work;
           ao = workBase - left;
       } else {
           b = work;
           ao = 0;
           bo = workBase - left;
       }
    
       // Merging
       for (int last; count > 1; count = last) {
           for (int k = (last = 0) + 2; k <= count; k += 2) {
               int hi = run[k], mi = run[k - 1];
               for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
                   if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
                       b[i + bo] = a[p++ + ao];
                   } else {
                       b[i + bo] = a[q++ + ao];
                   }
               }
               run[++last] = hi;
           }
           if ((count & 1) != 0) {
               for (int i = right, lo = run[count - 1]; --i >= lo;
                   b[i + bo] = a[i + ao]
               );
               run[++last] = right;
           }
           int[] t = a; a = b; b = t;
           int o = ao; ao = bo; bo = o;
       }
       }
    
  • 归并排序

    public static void parallelSort(float[] a) {
    int n = a.length, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
    else
        new ArraysParallelSortHelpers.FJFloat.Sorter
            (null, a, new float[n], 0, n, 0,
             ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
             MIN_ARRAY_SORT_GRAN : g).invoke();
    }
    
  • 二分法搜索

    private static int binarySearch0(long[] a, int fromIndex, int toIndex,
                               long key) {
    int low = fromIndex;
    int high = toIndex - 1;
    
    while (low <= high) {
        int mid = (low + high) >>> 1;
        long midVal = a[mid];
    
        if (midVal < key)
            low = mid + 1;
        else if (midVal > key)
            high = mid - 1;
        else
            return mid; // key found
    
    }
    return -(low + 1);  // key not found.
    }
    

3. ArrayDeque 数组队列

功能需求
源码分析
  • 申请元素

    private void allocateElements(int numElements) {
    int initialCapacity = MIN_INITIAL_CAPACITY;
    // Find the best power of two to hold elements.
    // Tests "<=" because arrays aren't kept full.
    if (numElements >= initialCapacity) {
        initialCapacity = numElements;
        initialCapacity |= (initialCapacity >>>  1);
        initialCapacity |= (initialCapacity >>>  2);
        initialCapacity |= (initialCapacity >>>  4);
        initialCapacity |= (initialCapacity >>>  8);
        initialCapacity |= (initialCapacity >>> 16);
        initialCapacity++;
    
        if (initialCapacity < 0)   // Too many elements, must back off
            initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
    
    }
    elements = new Object[initialCapacity];
    }
    
  • 插入队列元素

    public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if (head == tail)
        doubleCapacity();
    }
    
  • 移除队列元素

    public E removeFirst() {
    E x = pollFirst();
    if (x == null)
        throw new NoSuchElementException();
    return x;
    }