摘要:容器相關(guān)的操作及其源碼分析說(shuō)明本文是基于分析的。源碼是個(gè)好東東,各種編碼技巧,再次佩服老外下一個(gè)主題是容器,。在了解容器之前我們先來(lái)看下重點(diǎn)的數(shù)據(jù)吧,還有工具類(lèi)。第一段話(huà)說(shuō)明返回一個(gè)指定數(shù)組的固定列表。
容器相關(guān)的操作及其源碼分析 說(shuō)明
1、本文是基于JDK 7 分析的。JDK 8 待我工作了得好好研究下。Lambda、Stream。
2、因?yàn)閭€(gè)人能力有限,只能以模仿的形式+自己的理解寫(xiě)筆記。如有不對(duì)的地方還請(qǐng)諒解。
3、記錄的比較亂,但是對(duì)自己加深印象還是蠻有作用的。
4、筆記放github了,有興趣的可以看看。喜歡的可以點(diǎn)個(gè)star。
5、讀過(guò)源碼的可以快速瀏覽一遍,也能加深自己的理解。
6、源碼是個(gè)好東東,各種編碼技巧,再次佩服老外?。?!
7、下一個(gè)主題是容器,gogogo。感覺(jué)可以的話(huà)可以關(guān)注哈。
1、Array、Arrays在了解容器之前我們先來(lái)看下重點(diǎn)的數(shù)據(jù)吧,還有Arrays工具類(lèi)。
首先看一個(gè)栗子,利用數(shù)組計(jì)算大數(shù)字。完整的點(diǎn)這里,重點(diǎn)思想就是計(jì)算數(shù)組中的每一個(gè)數(shù),關(guān)鍵字是怎么進(jìn)和留。
/** * Created by guo on 2018/2/2. * 利用數(shù)組計(jì)算大數(shù)字 */ public static int[] get(int[] ints, int num) { //計(jì)算每一位 for (int i = 0; i < ints.length; i++) { ints[i] *= num; } //進(jìn)和留 for (int i = ints.length - 1; i > 0; i--) { //把個(gè)位數(shù)除10,加上前面的數(shù) ints[i - 1] += ints[i] / 10; //把最后的數(shù)模10,剩余個(gè)位數(shù)。1-9 ints[i] = ints[i] % 10; } return ints; }
需要注意的還有一個(gè)System.arrayscopy()方法,那就是底層數(shù)組的拷貝,這個(gè)也是關(guān)鍵點(diǎn)。完整代碼
/** * 底層實(shí)現(xiàn)的數(shù)組拷貝,是一個(gè)本地方法 * 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); /** * 參數(shù): * src:源,從哪個(gè)數(shù)組中拷貝數(shù)據(jù) * dest:目標(biāo):把數(shù)據(jù)拷貝到哪一個(gè)數(shù)組中 * srcpos:從原數(shù)組中哪一個(gè)位置開(kāi)始拷貝 * destPos:在目標(biāo)數(shù)組開(kāi)始存放的位置 * length:拷貝的個(gè)數(shù) */ 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) { //不是最后一個(gè)元素 str = str + ","; } } str = str + "]"; System.out.println(str); }
其他內(nèi)容不是今天的重點(diǎn),這里只是容器中需要數(shù)組的底層Copy。
ArraysArrays類(lèi)是Java中用于操作數(shù)組的類(lèi),使用這個(gè)工具類(lèi)可以減少平常很多工作量。 主題框架參考這里,寫(xiě)的非常不錯(cuò),
我們具體現(xiàn)看看它有哪些方法
1、sort 排序
2、binarySearch 二分查找(折半查找)
3、equals 比較
4、fill 填充
5、asList 轉(zhuǎn)列表 記得一個(gè)toArray嗎?
6、indexOf str首次出現(xiàn)的位置
6、hash 哈希(重點(diǎn))
7、toString 重寫(xiě)Object中方法
首先來(lái)看看排序的
/** * Sorts the specified array into ascending numerical order. * @param a the array to be sorted */ public static void sort(int[] a) { DualPivotQuicksort.sort(a); }
需要關(guān)注的是底層默認(rèn)是按升序(asc),還有調(diào)用這個(gè)DualPivotQuicksort.sort(a)方法是什么鬼?中文意思為雙軸快速排序,它在性能上優(yōu)于傳統(tǒng)的單軸快速排序。 它是不穩(wěn)定的。
重點(diǎn)在這里O(n log(n)),還有這句話(huà)` and is typically
faster than traditional (one-pivot) Quicksort implementations.` 具體看大佬的博文友情提示
/** * 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傳進(jìn)去的是int[] a,接下來(lái)看看傳Object對(duì)象的。All elements in the array must implement the Comparable interface.
/** * 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 * mutually comparable (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); }
在來(lái)看看帶泛型參數(shù)的,這個(gè)重點(diǎn)那,有三個(gè)點(diǎn)需要關(guān)注,Comparator,ClassCastException 和 TimSort算法 是從JDK 7 開(kāi)始默認(rèn)支持,
/** * 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 staticvoid sort(T[] a, Comparator super T> c) { if (LegacyMergeSort.userRequested) legacyMergeSort(a, c); else TimSort.sort(a, c); //注意這個(gè)TimSort }
整體上在看看這幾個(gè)到底啥意思?
/** *大概意思就是舊的歸并算法使用了系統(tǒng)屬性,可能會(huì)導(dǎo)致循環(huán)依賴(lài),不是能是靜態(tài)boolean,未來(lái)版本將移除 * 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(); } //傳進(jìn)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); } //都要移除啊,看來(lái)的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); } /** * 列表大小低于插入將優(yōu)先使用歸并算法,也要移除啊, * 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 //小數(shù)組將使用普通的插入算法 if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; ilow && ((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]. 這個(gè)可以理解,面試手寫(xiě)算法時(shí),可以寫(xiě)這個(gè)那。 */ private static void swap(Object[] x, int a, int b) { Object t = x[a]; x[a] = x[b]; x[b] = t; }
從上面的邏輯可以看出,它的實(shí)現(xiàn)方式分為兩種,一種是通過(guò)Arrays中的歸并算法實(shí)現(xiàn)的,另外一種采用了TimSOrt算法,
這個(gè)排序算法是穩(wěn)定的,JDK8已經(jīng)刪除了,我們來(lái)看看8是怎么實(shí)現(xiàn)的。
/** * 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 (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 staticvoid 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); //還是這個(gè) else new ArraysParallelSortHelpers.FJObject.Sorter (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并行啊,
這個(gè)也是重點(diǎn),除傳入int[]之外其他都變成了parallelSort.慢慢來(lái)吧,先JDK7,在JDK 8.還有就是可以傳進(jìn)其他類(lèi)型,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); } }二分查找,
注意接下來(lái),我們只看泛型有關(guān)的方法,其他實(shí)現(xiàn)大同小異。因?yàn)榉盒秃苤匾?/p>
/** * 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 staticint 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 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作用就是檢查邊界,看數(shù)據(jù)是否越界,會(huì)拋出ArrayIndexOutOfBoundsException
binarySearch0這是什么鬼?點(diǎn)進(jìn)去看看
要明白首先看參數(shù)
//fromIndex就是開(kāi)始索引(inclusive),toIndex結(jié)束(exclusive),key就是指定的數(shù)。 * @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; */
/** * 二分查找法(折半查找):前提是在已經(jīng)排好序的數(shù)組中,通過(guò)將待查找的元素 * 與中間索引值對(duì)應(yīng)的元素進(jìn)行比較,若大于中間索引值對(duì)應(yīng)的元素,去右半邊查找, * 否則,去左邊查找。依次類(lèi)推。直到找到位置;找不到返回一個(gè)負(fù)數(shù) * * Like public version, but without range checks. *這里沒(méi)有邊界檢查,這才是二分查找重點(diǎn)。 */ private staticequalsint 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; //開(kāi)始下標(biāo) int high = toIndex - 1; //結(jié)束下標(biāo) while (low <= high) { int mid = (low + high) >>> 1; //這里用了向右移2位(左邊補(bǔ)0),/2 向左就是 *2. T midVal = a[mid]; int cmp = c.compare(midVal, key); //比較key是在左邊還是右邊 if (cmp < 0) //小于0意味著key大, low = mid + 1; //則去掉左邊的值。中間的索引+1就是新的開(kāi)始下標(biāo) else if (cmp > 0) //key比中間的小 high = mid - 1; //則去掉右邊的,中間下標(biāo)-1,就是新的結(jié)束下標(biāo) else return mid; // key found } return -(low + 1); // key not found.這里是-1 -(0 + 1) }
接下來(lái)在看看比較的,這個(gè)是重點(diǎn)。這里只看Object[],其他還有很多,如int、byte、char
重點(diǎn)看這句話(huà):
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,
兩個(gè)數(shù)組引用都為null,則返回true。
/** * Returns true if the two specified arrays of Objects are * equal 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 e1 * and e2 are considered equal if (e1==null ? e2==null * : e1.equals(e2)). 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.* * @param a one array to be tested for equality * @param a2 the other array to be tested for equality * @return true 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) //任意一個(gè)為null,返回false return false; int length = a.length; if (a2.length != length) //數(shù)組長(zhǎng)度比較 return false; for (int i=0; i
fill 填充 就是循環(huán)進(jìn)行賦值填充,
/** * 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 fromIndex, inclusive, to index * toIndex, exclusive. (If fromIndex==toIndex, 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; }這里主要想再次看下這個(gè)邊界檢查
主要作用就是檢查a.length是否在開(kāi)始下標(biāo)和結(jié)束下標(biāo)之間。
/** * 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) { //開(kāi)始下標(biāo)還能比結(jié)束大嗎?你這不是胡鬧嗎? throw new IllegalArgumentException( //非法-參數(shù)-異常,很常見(jiàn)的。 "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } if (fromIndex < 0) { //你還沒(méi)開(kāi)始呢,能小于0嗎? throw new ArrayIndexOutOfBoundsException(fromIndex); //數(shù)據(jù)下標(biāo)越界啦, } if (toIndex > length) { //你要查的不再這個(gè)范圍呢。 throw new ArrayIndexOutOfBoundsException(toIndex); //你越界了 } }clone就像剛開(kāi)始數(shù)組復(fù)制的那個(gè)一樣,
首先這里會(huì)拋出大家熟悉的異常NullPointerExceptionif original is null
新數(shù)組的長(zhǎng)度能為負(fù)數(shù)嗎?當(dāng)然不能啊,所以?huà)伋?b>NegativeArraySizeException
這里最為關(guān)鍵的是底層使用了本地方法,實(shí)現(xiàn)大概由剛開(kāi)始那個(gè)復(fù)制差不多。但,考錄的因素太多了,或者是版權(quán),或者根本就不想讓我們知道。還有就是這個(gè)用底層畢竟效率快啊,直接和系統(tǒng)打交道。
/** * 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 (byte)0. * 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 newLength is negative * @throws NullPointerException if original 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; } --------------------------范圍復(fù)制--------------------------------------------- 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; } ---------------------------底層復(fù)制---------------------------------------------- 注意,這個(gè)類(lèi)是不能進(jìn)行實(shí)例化的, 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 byasListsrc
to the destination array * referenced bydest
. 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); }需要注意的是這里直接new了一個(gè)內(nèi)部的ArrayList,實(shí)現(xiàn)類(lèi)兩個(gè)接口。
第一段話(huà)說(shuō)明:返回一個(gè)指定數(shù)組的固定列表。并不是java.util.ArrayList,而且它不支持添加和移除元素,不支持?jǐn)U容。但支持序列化和隨機(jī)存儲(chǔ),我們具體來(lái)看看
/** * 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}. * *This method also provides a convenient way to create a fixed-size * list initialized to contain several elements: *
* List* * @param a the array by which the list will be backed * @return a list view of the specified array */ @SafeVarargs public staticstooges = Arrays.asList("Larry", "Moe", "Curly"); * List asList(T... a) { return new ArrayList<>(a); } 為了方便,把這個(gè)方法抽出來(lái),里面的方法還會(huì)繼續(xù)抽。
/** * @serial include */ private static class ArrayListextends AbstractList implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; 進(jìn)行反序列化時(shí)驗(yàn)證用的 private final E[] a; ArrayList(E[] array) { //進(jìn)行初始化,如果等null,則拋出空指針異常 if (array==null) throw new NullPointerException(); a = array; //然后再賦值給a } public int size() { return a.length; } public Object[] toArray() { //原來(lái)你跑在這里了, return a.clone(); } public 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是否首次出現(xiàn)的索引位置, if (o==null) { for (int i=0; i hash 這個(gè)方法很重要,后續(xù)出場(chǎng)的幾率很大,其實(shí)也很簡(jiǎn)單,
首先來(lái)看一下HashCode和equals方法調(diào)用的過(guò)程:
/** * new String("abc") * 1.調(diào)用對(duì)象的hashCode方法,new String("abc").hashCode() == 96354 * 2.集合在容器內(nèi)找,有沒(méi)有和96354一樣的哈希值, * new String("abc") * 3.調(diào)用對(duì)象的hashCode方法,new String("abc").hashCode() == 96354 * 4.集合在啊容器內(nèi),找到了一個(gè)對(duì)象也是96354 * 5.集合會(huì)讓后來(lái)的new String("abc")調(diào)用對(duì)象的equals(已經(jīng)有的對(duì)象) * 5.兩個(gè)對(duì)象哈希值一樣,equals方法返回true,集合判斷元素重復(fù), * new String("adc) * 集合調(diào)用對(duì)象的hashCode方法 new String("adc").hashCode()= 96354 * 集合去容器中找,有沒(méi)有96354的對(duì)象,找到了 * 集合讓后來(lái)的對(duì)象 new String("adc").equals(已存在的對(duì)象) * 兩個(gè)對(duì)象的哈希值一樣,equals返回false * 集合判定對(duì)象沒(méi)有重復(fù),因此采用桶的方式 */ HashSetset = 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的呢?不急,先來(lái)看看字符編碼,因?yàn)镴ava采用Unicode編碼,一般兩個(gè)字節(jié)表示一個(gè)字符,ASCLL則一個(gè)字節(jié)表示一個(gè)字符。所以"abc"對(duì)應(yīng)的就是(97+98+99) “ABC”則為(65+66+67)
注意在這里31是一個(gè)素?cái)?shù),就不除它自己不能被整除的。
注意下面這個(gè)是字符串中的hashCode方法,就是重復(fù)計(jì)算,
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; }底下下這個(gè)是Arrays類(lèi)里面的。重寫(xiě)都不一樣。也可以自己重新,
/** * Returns a hash code based on the contents of the specified array. * For any two byte arrays a and b * such that Arrays.equals(a, b), it is also the case that * Arrays.hashCode(a) == Arrays.hashCode(b). * *toStringThe value returned by this method is the same value that would be * obtained by invoking the {@link List#hashCode() hashCode} * method on a {@link List} containing a sequence of {@link Byte} * instances representing the elements of a in the same order. * If a is null, this method returns 0. * * @param a the array whose hash value to compute * @return a content-based hash code for a * @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; //最后返回 }
需要注意的是底層使用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 ("[]"). Adjacent elements * are separated by the characters ", " (a comma followed * by a space). Elements are converted to strings as by * String.valueOf(byte). Returns "null" if * a is null. * * @param a the array whose string representation to return * @return a string representation of a * @since 1.5 */ public static String toString(byte[] a) { if (a == null) return "null"; int iMax = a.length - 1; //如果是一個(gè)空數(shù)據(jù)(和null有區(qū)別),(0 - 1) if (iMax == -1) return "[]"; //則直接輸出[] StringBuilder b = new StringBuilder(); //這里是可變的,并不是重新創(chuàng)建,只是在追加。 b.append("["); for (int i = 0; ; i++) { b.append(a[i]); //循環(huán)追加a[i],當(dāng)?shù)扔?1的時(shí)候最后追加"]"打印 if (i == iMax) return b.append("]").toString(); b.append(", "); } }其實(shí)還有許多重載方法,這里就不展示了,我們來(lái)看下Person類(lèi)重寫(xiě)euqals、hashCode、toString是長(zhǎng)啥樣、
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 + "}"; } }這個(gè)主題就到這里吧,下一個(gè)主題正式進(jìn)入容器的介紹。gogogo
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68719.html
摘要:三系列用于保存鍵值對(duì),無(wú)論是,還是已棄用的或者線(xiàn)程安全的等,都是基于紅黑樹(shù)。是完全基于紅黑樹(shù)的,并在此基礎(chǔ)上實(shí)現(xiàn)了接口??梢钥吹剑挥屑t黑樹(shù),且紅黑樹(shù)是通過(guò)內(nèi)部類(lèi)來(lái)實(shí)現(xiàn)的。 JDK容器 前言 閱讀JDK源碼有段時(shí)間了,準(zhǔn)備以博客的形式記錄下來(lái),也方便復(fù)習(xí)時(shí)查閱,本文參考JDK1.8源碼。 一、Collection Collection是所有容器的基類(lèi),定義了一些基礎(chǔ)方法。List、Se...
摘要:容器相關(guān)的操作及其源碼分析說(shuō)明本文是基于分析的。有哪些抽取出來(lái)的工具類(lèi)。即對(duì)于反轉(zhuǎn)方式如下替換值查找在出現(xiàn)的最小位置。查找在出現(xiàn)的最大位置。即返回的和原在元素上保持一致,但不可修改。 容器相關(guān)的操作及其源碼分析 說(shuō)明 1、本文是基于JDK 7 分析的。JDK 8 待我工作了得好好研究下。Lambda、Stream。 2、因?yàn)閭€(gè)人能力有限,只能以模仿的形式+自己的理解寫(xiě)筆記。如有不對(duì)的...
摘要:畢業(yè)兩個(gè)星期了,開(kāi)始成為一名正式的碼農(nóng)了。將指定位置的數(shù)據(jù)移除。但是問(wèn)題是,為時(shí),并不是直接一個(gè)大小為的數(shù)組,而是使用靜態(tài)變量來(lái)代替。此外,函數(shù)還做了越界檢查。返回迭代器,與之有一個(gè)搭配的輔助類(lèi)。 畢業(yè)兩個(gè)星期了,開(kāi)始成為一名正式的java碼農(nóng)了。一直對(duì)偏底層比較感興趣,想著深入自己的java技能,看書(shū)、讀源碼、總結(jié)、造輪子實(shí)踐都是付諸行動(dòng)的方法。說(shuō)到看源碼,就應(yīng)該由簡(jiǎn)入難,逐漸加深,...
摘要:底層使用的是雙向鏈表數(shù)據(jù)結(jié)構(gòu)之前為循環(huán)鏈表,取消了循環(huán)??焖匐S機(jī)訪問(wèn)就是通過(guò)元素的序號(hào)快速獲取元素對(duì)象對(duì)應(yīng)于方法。而接口就是用來(lái)標(biāo)識(shí)該類(lèi)支持快速隨機(jī)訪問(wèn)。僅僅是起標(biāo)識(shí)作用。,中文名為雙端隊(duì)列。不同的是,是線(xiàn)程安全的,內(nèi)部使用了進(jìn)行同步。 前言 學(xué)習(xí)情況記錄 時(shí)間:week 2 SMART子目標(biāo) :Java 容器 記錄在學(xué)習(xí)Java容器 知識(shí)點(diǎn)中,關(guān)于List的需要重點(diǎn)記錄的知識(shí)點(diǎn)。...
摘要:輔助方法這個(gè)方法遞歸遍歷的子節(jié)點(diǎn),將節(jié)點(diǎn)交由回調(diào)函數(shù)處理。對(duì)集合進(jìn)行遍歷,調(diào)用方法,如果為函數(shù),則將回調(diào)函數(shù)返回的結(jié)果作為參數(shù)傳給否則,如果為,則將也即包裹元素的副本傳給,否則直接將傳給。 這篇依然是跟 dom 相關(guān)的方法,側(cè)重點(diǎn)是操作 dom 的方法。 讀Zepto源碼系列文章已經(jīng)放到了github上,歡迎star: reading-zepto 源碼版本 本文閱讀的源碼為 zepto...
閱讀 3137·2023-04-26 02:27
閱讀 2874·2021-11-22 13:54
閱讀 968·2021-11-12 10:36
閱讀 3835·2021-10-09 09:44
閱讀 3238·2021-10-09 09:41
閱讀 1336·2021-09-22 10:02
閱讀 2948·2019-08-30 15:56
閱讀 3170·2019-08-30 11:02