容器之數組~Arrays源碼分析(一)

容器相關的操做及其源碼分析

說明

  • 一、本文是基於JDK 7 分析的。JDK 8 待我工做了得好好研究下。Lambda、Stream。
  • 二、由於我的能力有限,只能以模仿的形式+本身的理解寫筆記。若有不對的地方還請諒解。
  • 三、記錄的比較亂,可是對本身加深印象仍是蠻有做用的。
  • 四、筆記放github了,有興趣的能夠看看。喜歡的能夠點個star。
  • 五、讀過源碼的能夠快速瀏覽一遍,也能加深本身的理解。
  • 六、源碼是個好東東,各類編碼技巧,再次佩服老外!!!
  • 七、下一個主題是容器,gogogo。感受能夠的話能夠關注哈。

一、Array、Arrays

在瞭解容器以前咱們先來看下重點的數據吧,還有Arrays工具類。java

首先看一個栗子,利用數組計算大數字。完整的點這裏,重點思想就是計算數組中的每個數,關鍵字是怎麼進和留。git

/**
 * Created by guo on 2018/2/2.
 * 利用數組計算大數字
 */
public static int[] get(int[] ints, int num) {
    //計算每一位
    for (int i = 0; i < ints.length; i++) {
        ints[i] *= num;

    }
    //進和留
    for (int i = ints.length - 1; i > 0; i--) {

        //把個位數除10,加上前面的數
        ints[i - 1] += ints[i] / 10;
        //把最後的數模10,剩餘個位數。1-9
        ints[i] = ints[i] % 10;
    }
    return ints;
}

須要注意的還有一個System.arrayscopy()方法,那就是底層數組的拷貝,這個也是關鍵點。完整代碼github

/**
 * 底層實現的數組拷貝,是一個本地方法
 * void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);
 *  src      the source array.
 * srcPos   starting position in the source array.
 * dest     the destination array.
 * destPos  starting position in the destination data.
 * length   the number of array elements to be copied.
 */
System.arraycopy(src,-1,dest,2,3);
/**
 * 參數:
 * src:源,從哪一個數組中拷貝數據
 * dest:目標:把數據拷貝到哪個數組中
 * srcpos:從原數組中哪個位置開始拷貝
 * destPos:在目標數組開始存放的位置
 * length:拷貝的個數
 */
static void arrayCopy(int[] src, int srcPos, int[] dest, int destPos, int length) {
    if(srcPos < 0 || destPos < 0 || length < 0) {
        throw  new RuntimeException("出異常了,從新檢查");
    }
    for (int index = srcPos; index < srcPos + length; index++) {
        dest[destPos] = src[index];
        destPos++;

    }
}

static void print(int[] arr) {
    String str = "[";
    for (int i = 0; i < arr.length; i++) {
        str += arr[i];
        if (i != arr.length - 1) {   //不是最後一個元素
            str = str + ',';
        }
    }
    str = str + "]";
    System.out.println(str);
}

其餘內容不是今天的重點,這裏只是容器中須要數組的底層Copy。面試

Arrays

Arrays類是Java中用於操做數組的類,使用這個工具類能夠減小日常不少工做量。 主題框架參考這裏,寫的很是不錯算法

咱們具體現看看它有哪些方法數組

  • 一、sort 排序
  • 二、binarySearch 二分查找(折半查找)
  • 三、equals 比較
  • 四、fill 填充
  • 五、asList 轉列表 記得一個toArray嗎?
  • 六、indexOf str首次出現的位置
  • 六、hash 哈希(重點)
  • 七、toString 重寫Object中方法

首先來看看排序的app

/**
 * Sorts the specified array into ascending numerical order.
 * @param a the array to be sorted
 */
public static void sort(int[] a) {
    DualPivotQuicksort.sort(a);
}

須要關注的是底層默認是按升序(asc),還有調用這個DualPivotQuicksort.sort(a)方法是什麼鬼?中文意思爲雙軸快速排序,它在性能上優於傳統的單軸快速排序。 它是不穩定的。框架

重點在這裏O(n log(n)),還有這句話` and is typically
faster than traditional (one-pivot) Quicksort implementations.` 具體看大佬的博文友情提示dom

/**
 * This class implements the Dual-Pivot Quicksort algorithm by
 * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
 * offers O(n log(n)) performance on many data sets that cause other
 * quicksorts to degrade to quadratic performance, and is typically
 * faster than traditional (one-pivot) Quicksort implementations.
 */
final class DualPivotQuicksort {
}

上面的sort傳進去的是int[] a,接下來看看傳Object對象的。All elements in the array must implement the Comparable interface. ide

/**
 * Sorts the specified array of objects into ascending order, according
 * to the {@linkplain Comparable natural ordering} of its elements.
 * All elements in the array must implement the {@link Comparable}
 * interface.  Furthermore, all elements in the array must be
 * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
 * not throw a {@code ClassCastException} for any elements {@code e1}
 * and {@code e2} in the array).
 */
public static void sort(Object[] a) {
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a);
    else
        ComparableTimSort.sort(a);
}

在來看看帶泛型參數的,這個重點那,有三個點須要關注,Comparator,ClassCastExceptionTimSort算法 是從JDK 7 開始默認支持,

/**
 * Sorts the specified array of objects according to the order induced by
 * the specified comparator.  All elements in the array must be
 * mutually comparable by the specified comparator must not throw a  * *ClassCastException  for any elements and  in the array.
 */
public static <T> void sort(T[] a, Comparator<? super T> c) {
    if (LegacyMergeSort.userRequested)
        legacyMergeSort(a, c);
    else
        TimSort.sort(a, c);     //注意這個TimSort
}

總體上在看看這幾個到底啥意思?

/**
*大概意思就是舊的歸併算法使用了系統屬性,可能會致使循環依賴,不是能是靜態boolean,將來版本將移除
 * Old merge sort implementation can be selected (for
 * compatibility with broken comparators) using a system property.
 * Cannot be a static boolean in the enclosing class due to
 * circular dependencies. To be removed in a future release.
 */
static final class LegacyMergeSort {
     private static final boolean userRequested =
         java.security.AccessController.doPrivileged(
             new sun.security.action.GetBooleanAction(
                 "java.util.Arrays.useLegacyMergeSort")).booleanValue();
 }

//傳進Object的排序,
 public static void sort(Object[] a) {
     if (LegacyMergeSort.userRequested)
         legacyMergeSort(a);
     else
         ComparableTimSort.sort(a);
 }

 /** To be removed in a future release. */
 private static void legacyMergeSort(Object[] a) {
     Object[] aux = a.clone();
     mergeSort(aux, a, 0, a.length, 0);
 }
//都要移除啊,看來的JDK8了
 /** To be removed in a future release. */
 private static void legacyMergeSort(Object[] a,
                                     int fromIndex, int toIndex) {
     rangeCheck(a.length, fromIndex, toIndex);
     Object[] aux = copyOfRange(a, fromIndex, toIndex);
     mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
 }

 /**
 * 列表大小低於插入將優先使用歸併算法,也要移除啊,
  * Tuning parameter: list size at or below which insertion sort will be
  * used in preference to mergesort.
  * To be removed in a future release.
  */
 private static final int INSERTIONSORT_THRESHOLD = 7;

 /**
  * Src is the source array that starts at index 0
  * Dest is the (possibly larger) array destination with a possible offset
  * low is the index in dest to start sorting
  * high is the end index in dest to end sorting
  * off is the offset to generate corresponding low, high in src
  * To be removed in a future release.
  */
 private static void mergeSort(Object[] src,
                               Object[] dest,
                               int low,
                               int high,
                               int off) {
     int length = high - low;

     // Insertion sort on smallest arrays
     //小數組將使用普通的插入算法
     if (length < INSERTIONSORT_THRESHOLD) {
         for (int i=low; i<high; i++)
             for (int j=i; j>low &&
                      ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                 swap(dest, j, j-1);
         return;
     }
     // Merge sorted halves (now in src) into dest

 }
 ----------------------------------------------------------------------------
 /**
 * Swaps x[a] with x[b]. 這個能夠理解,面試手寫算法時,能夠寫這個那。
 */
private static void swap(Object[] x, int a, int b) {
    Object t = x[a];
    x[a] = x[b];
    x[b] = t;
}

從上面的邏輯能夠看出,它的實現方式分爲兩種,一種是經過Arrays中的歸併算法實現的,另一種採用了TimSOrt算法

這個排序算法是穩定的,JDK8已經刪除了,咱們來看看8是怎麼實現的。

/**
 * Sorts the specified array of objects according to the order induced by
 * the specified comparator.  All elements in the array must be
 * <i>mutually comparable</i> by the specified comparator (that is,
 * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
 * for any elements {@code e1} and {@code e2} in the array).
 * @since 1.8
 */
@SuppressWarnings("unchecked")
public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
    if (cmp == null)
        cmp = NaturalOrder.INSTANCE;
    int n = a.length, p, g;
    if (n <= MIN_ARRAY_SORT_GRAN ||
        (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
        TimSort.sort(a, 0, n, cmp, null, 0, 0);  //仍是這個
    else
        new ArraysParallelSortHelpers.FJObject.Sorter<T>
            (null, a,
             (T[])Array.newInstance(a.getClass().getComponentType(), n),
             0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
             MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
}

須要注意的是方法名變成了parallelSort並行啊,

這個也是重點,除傳入int[]以外其餘都變成了parallelSort.慢慢來吧,先JDK7,在JDK 8.還有就是能夠傳進其餘類型,char、long、byte。etc(等)。

/**
 * Checks that {@code fromIndex} and {@code toIndex} are in
 * the range and throws an exception if they aren't.
 */
private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
    if (fromIndex > toIndex) {
        throw new IllegalArgumentException(
                "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
    }
    if (fromIndex < 0) {
        throw new ArrayIndexOutOfBoundsException(fromIndex);
    }
    if (toIndex > arrayLength) {
        throw new ArrayIndexOutOfBoundsException(toIndex);
    }
}

二分查找,

注意接下來,咱們只看泛型有關的方法,其餘實現大同小異。由於泛型很重要。

/**
 * Searches the specified array for the specified object using the binary
 * search algorithm.  The array must be sorted into ascending order
 * according to the specified comparator (as by the
 * {@link #sort(Object[], Comparator) sort(T[], Comparator)}
 * method) prior to making this call.  If it is
 * not sorted, the results are undefined.
 * If the array contains multiple
 * elements equal to the specified object, there is no guarantee which one
 * will be found.
 */
public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
    return binarySearch0(a, 0, a.length, key, c);
}
/**
 * Searches a range of
 * the specified array for the specified object using the binary
 * search algorithm.
 * The range must be sorted into ascending order
 * according to the specified comparator (as by the
 * {@link #sort(Object[], int, int, Comparator)
 * sort(T[], int, int, Comparator)}
 * method) prior to making this call.
 * If it is not sorted, the results are undefined.
 * If the range contains multiple elements equal to the specified object,
 * there is no guarantee which one will be found.

 */
public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
                                   T key, Comparator<? super T> c) {
    rangeCheck(a.length, fromIndex, toIndex);
    return binarySearch0(a, fromIndex, toIndex, key, c);
}

rangeCheck做用就是檢查邊界,看數據是否越界,會拋出ArrayIndexOutOfBoundsException

binarySearch0這是什麼鬼?點進去看看

要明白首先看參數

//fromIndex就是開始索引(inclusive),toIndex結束(exclusive),key就是指定的數。
* @param fromIndex the index of the first element (inclusive) to be
*          searched
* @param toIndex the index of the last element (exclusive) to be searched
* @param key the value to be searched for
* @return index of the search key, if it is contained in the array
*         within the specified range;
 */
/**
* 二分查找法(折半查找):前提是在已經排好序的數組中,經過將待查找的元素
* 與中間索引值對應的元素進行比較,若大於中間索引值對應的元素,去右半邊查找,
* 不然,去左邊查找。依次類推。直到找到位置;找不到返回一個負數
*
* Like public version, but without range checks.
*這裏沒有邊界檢查,這纔是二分查找重點。
*/
 private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
                                      T key, Comparator<? super T> c) {
     if (c == null) {  //先判斷
         return binarySearch0(a, fromIndex, toIndex, key);
     }
     int low = fromIndex;       //開始下標
     int high = toIndex - 1;    //結束下標

     while (low <= high) {
         int mid = (low + high) >>> 1;      //這裏用了向右移2位(左邊補0),/2 向左就是 *2.
         T midVal = a[mid];
         int cmp = c.compare(midVal, key);    //比較key是在左邊仍是右邊
         if (cmp < 0)                         //小於0意味着key大,
             low = mid + 1;                   //則去掉左邊的值。中間的索引+1就是新的開始下標
         else if (cmp > 0)                    //key比中間的小
             high = mid - 1;                  //則去掉右邊的,中間下標-1,就是新的結束下標
         else
             return mid;                      // key found
     }
     return -(low + 1);                       // key not found.這裏是-1 -(0 + 1)
 }

equals

接下來在看看比較的,這個是重點。這裏只看Object[],其餘還有不少,如int、byte、char

重點看這句話:

In other words, the two arrays are equal if
they contain the same elements in the same order.

Also, two array references are considered equal if both are null

以相同的順序,而且互相包含,則返回true,

兩個數組引用都爲null,則返回true。

/**
 * Returns <tt>true</tt> if the two specified arrays of Objects are
 * <i>equal</i> to one another.  The two arrays are considered equal if
 * both arrays contain the same number of elements, and all corresponding
 * pairs of elements in the two arrays are equal.  Two objects <tt>e1</tt>
 * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
 * : e1.equals(e2))</tt>.  In other words, the two arrays are equal if
 * they contain the same elements in the same order.  Also, two array
 * references are considered equal if both are <tt>null</tt>.<p>
 *
 * @param a one array to be tested for equality
 * @param a2 the other array to be tested for equality
 * @return <tt>true</tt> if the two arrays are equal  //相等返回true
 */
public static boolean equals(Object[] a, Object[] a2) {
    if (a==a2)                       //注意,這裏是地址的比較,
        return true;
    if (a==null || a2==null)        //任意一個爲null,返回false
        return false;

    int length = a.length;
    if (a2.length != length)        //數組長度比較
        return false;

    for (int i=0; i<length; i++) {
        Object o1 = a[i];
        Object o2 = a2[i];
        if (!(o1==null ? o2==null : o1.equals(o2)))   //這裏使用了三目運算符
            return false;     //o1等於null嗎?,爲真,繼o2等於null嗎,爲真,繼續
                              //兩個相等嗎?爲真,而後在取反。
    }

    return true;              //當以上都不成立的時候返回true。
}
----------------------------------------------------------------------------
public static boolean equals(int[] a, int[] a2) {
    if (a==a2)
        return true;
    if (a==null || a2==null)
        return false;

    int length = a.length;
    if (a2.length != length)
        return false;

    for (int i=0; i<length; i++)
        if (a[i] != a2[i])
            return false;

    return true;
}

fill 填充

就是循環進行賦值填充,

/**
 * Assigns the specified int value to each element of the specified array
 * of ints.
 * @param a the array to be filled
 * @param val the value to be stored in all elements of the array
 */
public static void fill(int[] a, int val) {
    for (int i = 0, len = a.length; i < len; i++)
        a[i] = val;
}

-----------------------------------------------------------------------------
/**
 * Assigns the specified Object reference to each element of the specified
 * range of the specified array of Objects.  The range to be filled
 * extends from index <tt>fromIndex</tt>, inclusive, to index
 * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
 * range to be filled is empty.)
 */
public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
    rangeCheck(a.length, fromIndex, toIndex);
    for (int i = fromIndex; i < toIndex; i++)
        a[i] = val;
}

這裏主要想再次看下這個邊界檢查

主要做用就是檢查a.length是否在開始下標和結束下標之間。

/**
 * Checks that {@code fromIndex} and {@code toIndex} are in
 * the range and throws an appropriate exception, if they aren't.
 */
private static void rangeCheck(int length, int fromIndex, int toIndex) {
    if (fromIndex > toIndex) {               //開始下標還能比結束大嗎?你這不是胡鬧嗎?
        throw new IllegalArgumentException(    //非法-參數-異常,很常見的。
            "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
    }
    if (fromIndex < 0) {                      //你還沒開始呢,能小於0嗎?
        throw new ArrayIndexOutOfBoundsException(fromIndex);    //數據下標越界啦,
    }
    if (toIndex > length) {                   //你要查的再也不這個範圍呢。
        throw new ArrayIndexOutOfBoundsException(toIndex);      //你越界了
    }
}

clone

就像剛開始數組複製的那個同樣,

首先這裏會拋出你們熟悉的異常NullPointerExceptionif original is null

新數組的長度能爲負數嗎?固然不能啊,因此拋出NegativeArraySizeException

這裏最爲關鍵的是底層使用了本地方法,實現大概由剛開始那個複製差很少。但,考錄的因素太多了,或者是版權,或者根本就不想讓咱們知道。還有就是這個用底層畢竟效率快啊,直接和系統打交道。

/**
 * Copies the specified array, truncating or padding with zeros (if necessary)
 * so the copy has the specified length.  For all indices that are
 * valid in both the original array and the copy, the two arrays will
 * contain identical values.  For any indices that are valid in the
 * copy but not the original, the copy will contain <tt>(byte)0</tt>.
 * Such indices will exist if and only if the specified length
 * is greater than that of the original array.
 *
 * @param original the array to be copied
 * @param newLength the length of the copy to be returned
 * @return a copy of the original array, truncated or padded with zeros
 *     to obtain the specified length
 * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
 * @throws NullPointerException if <tt>original</tt> is null
 * @since 1.6
 */
public static byte[] copyOf(byte[] original, int newLength) {
    byte[] copy = new byte[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}
--------------------------範圍複製---------------------------------------------

public static char[] copyOfRange(char[] original, int from, int to) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    char[] copy = new char[newLength];
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}
---------------------------底層複製----------------------------------------------
注意,這個類是不能進行實例化的,
public final class System {
/**
 * Copies an array from the specified source array, beginning at the
 * specified position, to the specified position of the destination array.
 * A subsequence of array components are copied from the source
 * array referenced by <code>src</code> to the destination array
 * referenced by <code>dest</code>. T
* @param      src      the source array.
* @param      srcPos   starting position in the source array.
* @param      dest     the destination array.
* @param      destPos  starting position in the destination data.
* @param      length   the number of array elements to be copied.
*/
public static native void arraycopy(Object src,  int  srcPos,
                                   Object dest, int destPos,
                                   int length);
}

asList

須要注意的是這裏直接new了一個內部的ArrayList,實現類兩個接口。

第一段話說明:返回一個指定數組的固定列表。並非java.util.ArrayList,並且它不支持添加和移除元素,不支持擴容。但支持序列化和隨機存儲,咱們具體來看看

/**
    * Returns a fixed-size list backed by the specified array.  (Changes to
    * the returned list "write through" to the array.)  This method acts
    * as bridge between array-based and collection-based APIs, in
    * combination with {@link Collection#toArray}.  The returned list is
    * serializable and implements {@link RandomAccess}.
    *
    * <p>This method also provides a convenient way to create a fixed-size
    * list initialized to contain several elements:
    * <pre>
    *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
    * </pre>
    *
    * @param a the array by which the list will be backed
    * @return a list view of the specified array
    */
   @SafeVarargs
   public static <T> List<T> asList(T... a) {
       return new ArrayList<>(a);
   }

爲了方便,把這個方法抽出來,裏面的方法還會繼續抽。

/**
    * @serial include
    */
   private static class ArrayList<E> extends AbstractList<E>
       implements RandomAccess, java.io.Serializable
   {
       private static final long serialVersionUID = -2764017481108945198L;   進行反序列化時驗證用的
       private final E[] a;

       ArrayList(E[] array) {        //進行初始化,若是等null,則拋出空指針異常
           if (array==null)
               throw new NullPointerException();
           a = array;               //而後再賦值給a
       }

       public int size() {
           return a.length;
       }

       public Object[] toArray() {    //原來你跑在這裏了,
           return a.clone();
       }

       public <T> T[] toArray(T[] a) {
           int size = size();
           if (a.length < size)              //這裏不懂
               return Arrays.copyOf(this.a, size,
                                    (Class<? extends T[]>) a.getClass());
           System.arraycopy(this.a, 0, a, 0, size);
           if (a.length > size)
               a[size] = null;
           return a;
       }

       public E get(int index) {
           return a[index];                     //直接返回索引位置的元素
       }

       public E set(int index, E element) {
           E oldValue = a[index];               //直接替換舊的元素
           a[index] = element;
           return oldValue;
       }

       public int indexOf(Object o) {          //o是否首次出現的索引位置,
           if (o==null) {
               for (int i=0; i<a.length; i++)
                   if (a[i]==null)            //  原來是循環判斷是否爲null
                       return i;
           } else {
               for (int i=0; i<a.length; i++)
                   if (o.equals(a[i]))        //接着在對比是否等於a[i]
                       return i;
           }
           return -1;                       //沒有則返回-1
       }

       public boolean contains(Object o) {    //判斷是否包含,前提是調用`indexOf(o)`不能等-1
           return indexOf(o) != -1;
       }
   }

hash

這個方法很重要,後續出場的概率很大,其實也很簡單,

首先來看一下HashCode和equals方法調用的過程:

/**
 * new String("abc")
 * 1.調用對象的hashCode方法,new String("abc").hashCode()    == 96354
 * 2.集合在容器內找,有沒有和96354同樣的哈希值,
 * new String("abc")
 * 3.調用對象的hashCode方法,new String("abc").hashCode()    == 96354
 * 4.集合在啊容器內,找到了一個對象也是96354
 * 5.集合會讓後來的new String("abc")調用對象的equals(已經有的對象)
 * 5.兩個對象哈希值同樣,equals方法返回true,集合判斷元素重複,
 * new String("adc)
 * 集合調用對象的hashCode方法 new String("adc").hashCode()=  96354
 * 集合去容器中找,有沒有96354的對象,找到了
 * 集合讓後來的對象 new String("adc").equals(已存在的對象)
 * 兩個對象的哈希值同樣,equals返回false
 * 集合斷定對象沒有重複,所以採用桶的方式
 */

 HashSet<String> set = new HashSet<>();
set.add(new String("abc"));
set.add(new String("abc"));
set.add(new String("bbc"));
set.add(new String("bbc"));
System.out.println(set);          //[bbc, abc]

這裏究竟是怎麼算出96354的呢?不急,先來看看字符編碼,由於Java採用Unicode編碼,通常兩個字節表示一個字符,ASCLL則一個字節表示一個字符。因此'abc'對應的就是(97+98+99) 「ABC」則爲(65+66+67)

注意在這裏31是一個素數,就不除它本身不能被整除的。

注意下面這個是字符串中的hashCode方法,就是重複計算,

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

底下下這個是Arrays類裏面的。重寫都不同。也能夠本身從新,

/**
  * Returns a hash code based on the contents of the specified array.
  * For any two <tt>byte</tt> arrays <tt>a</tt> and <tt>b</tt>
  * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
  * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
  *
  * <p>The value returned by this method is the same value that would be
  * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
  * method on a {@link List} containing a sequence of {@link Byte}
  * instances representing the elements of <tt>a</tt> in the same order.
  * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
  *
  * @param a the array whose hash value to compute
  * @return a content-based hash code for <tt>a</tt>
  * @since 1.5
  */
 public static int hashCode(byte a[]) {
     if (a == null)
         return 0;

     int result = 1;
     for (byte element : a)
         result = 31 * result + element;

     return result;    //最後返回
 }

toString

須要注意的是底層使用StringBuilder以追加的形式打印輸出。

/**
 * Returns a string representation of the contents of the specified array.
 * The string representation consists of a list of the array's elements,
 * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements
 * are separated by the characters <tt>", "</tt> (a comma followed
 * by a space).  Elements are converted to strings as by
 * <tt>String.valueOf(byte)</tt>.  Returns <tt>"null"</tt> if
 * <tt>a</tt> is <tt>null</tt>.
 *
 * @param a the array whose string representation to return
 * @return a string representation of <tt>a</tt>
 * @since 1.5
 */
public static String toString(byte[] a) {
    if (a == null)
        return "null";
    int iMax = a.length - 1;  //若是是一個空數據(和null有區別),(0 - 1)
    if (iMax == -1)
        return "[]";          //則直接輸出[]

    StringBuilder b = new StringBuilder();     //這裏是可變的,並非從新建立,只是在追加。
    b.append('[');
    for (int i = 0; ; i++) {
        b.append(a[i]);                         //循環追加a[i],當等於-1的時候最後追加']'打印
        if (i == iMax)
            return b.append(']').toString();
        b.append(", ");
    }
}

其實還有許多重載方法,這裏就不展現了,咱們來看下Person類重寫euqals、hashCode、toString是長啥樣、

public class Person {
    private String name;
    private int age;

    //Setter、Getter、Constructor略

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        if (name != null ? !name.equals(person.name) : person.name != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

這個主題就到這裏吧,下一個主題正式進入容器的介紹。gogogo

相關文章
相關標籤/搜索