一、概述

1、介紹

  Arrays 類是 JDK1.2 提供的一個工具類,提供處理陣列的各種方法,基本上都是靜態方法,能直接通過類名Arrays呼叫。

二、類原始碼

1、asList()方法

  將一個泛型陣列轉化為List集合返回。但是,這個List集合既不是ArrayList例項,也不是Vector例項。它是一個固定長度的 List 集合,是 Arrays 的一個內部類 java.util.Arrays.ArrayList。
  程式碼示例:使用

 1 public class Main {
2 public static void main(String[] args) throws Exception {
3 Integer[] d = {3, 1, 2};
4 final List<Integer> integers = Arrays.asList(d);
5 System.out.println(integers);
6 }
7 }
8
9 // 結果
10 [3, 1, 2]

  原始碼示例:

1 public static <T> List<T> asList(T... a) {
2 return new ArrayList<>(a);
3 }
4
5 private static class ArrayList<E> extends AbstractList<E>
6 implements RandomAccess, java.io.Serializable
7 {
8 // 原始碼省略,讀者可自行用idea檢視
9 }

  說明:
  ①、定長列表,只能對其進行檢視或者修改,不能進行新增或者刪除操作

 1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 List<String> list = Arrays.asList(str);
5 // 可以進行修改
6 list.set(1, "e");
7 System.out.println(list.toString()); // [a, e, c]
8
9 list.add("a"); //新增元素會報錯 java.lang.UnsupportedOperationException
10 }
11 }

  檢視原始碼發現,該類沒有add() 和 remove()方法。如果對其進行增加或者刪除操作,會呼叫其父類 AbstractList 對應的方法,而追溯父類的方法最終會丟擲 UnsupportedOperationException 異常。原始碼如下:

1 // 類 AbstractList
2 public boolean add(E e) {
3 add(size(), e);
4 return true;
5 }
6
7 public void add(int index, E element) {
8 throw new UnsupportedOperationException();
9 }

  ②、引用型別的陣列和基本型別的陣列區別

 1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 final List<String> list = Arrays.asList(str);
5 System.out.println(list.size()); // 3
6
7 int[] i = {1, 2, 3};
8 final List<int[]> ints = Arrays.asList(i);
9 System.out.println(ints.size()); // 1
10
11 Integer[] in = {1, 2, 3};
12 final List<Integer> integers = Arrays.asList(in);
13 System.out.println(integers.size()); // 3
14 }
15 }

  類型別才是泛型,基本資料型別不能作為泛型的引數。讀者根據上面結果自行體會一下。

  ③、返回的是原陣列的裡的引用,不是獨立出來的集合物件

 1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4 List<String> listStr = Arrays.asList(str);
5 System.out.println(Arrays.toString(str)); // [a, b, c]
6
7 listStr.set(0, "d");
8
9 System.out.println(Arrays.toString(str)); // [d, b, c]
10 }
11 }

  這裡,修改的是返回的集合的內容,但是原陣列的內容也變化了,所以只是返回了原陣列的一個檢視。如果希望返回一個全新的集合,可以如下:

 1 public class Main {
2 public static void main(String[] args) {
3 String[] str = {"a", "b", "c"};
4
5 ArrayList<String> strings = new ArrayList<>(Arrays.asList(str));
6 strings.add("d");
7
8 System.out.println(Arrays.toString(str)); // [a, b, c]
9 System.out.println(strings); // [a, b, c, d]
10 }
11 }

2、sort()方法

  用於陣列排序,有一系列過載方法。注意,如果是 Object 型別,需要實現Comparable介面或者傳入一個比較器 Comparator ,使其具有可比性。可以參考這篇。Java比較器。
  原始碼示例:

1 public static void sort(int[] a) {
2 DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
3 }

  這個方法的原始碼很長,分別對陣列的長度進行了各種演算法的劃分,包括快速排序,插入排序,氣泡排序都有使用。詳細原始碼可以參考這篇部落格。

3、binarySearch()方法

  用於陣列查詢,是基於二分查詢演算法實現,有一系列過載方法,適用於各種基本資料型別以及物件陣列。
  值得注意的是:呼叫此方法,要求待查詢的陣列有序。存在,返回元素下標;不存在,返回一個負數(不是 -1)。
  原始碼示例:

 1 public static int binarySearch(int[] a, int key) {
2 return binarySearch0(a, 0, a.length, key);
3 }
4
5 // 典型的二分查詢演算法
6 private static int binarySearch0(int[] a, int fromIndex, int toIndex,
7 int key) {
8 int low = fromIndex;
9 int high = toIndex - 1;
10
11 while (low <= high) {
12 int mid = (low + high) >>> 1;
13 int midVal = a[mid];
14
15 if (midVal < key)
16 low = mid + 1;
17 else if (midVal > key)
18 high = mid - 1;
19 else
20 return mid; // key found
21 }
22
23 // 找不到,返回並不是 -1
24 return -(low + 1); // key not found.
25 }

4、copyOf()方法

  拷貝陣列元素。底層採用 System.arraycopy() 實現,這是一個native方法。
  注意:這個方法在ArrayList原始碼擴容時,也是用的它。
  程式碼示例:

 1 public class Main {
2 public static void main(String[] args) {
3 int[] old = {1, 3, 2};
4
5 int[] ints = Arrays.copyOf(old, 5);
6 System.out.println(Arrays.toString(ints)); // [1, 3, 2, 0, 0]
7
8 int[] ints1 = Arrays.copyOf(old, 1);
9 System.out.println(Arrays.toString(ints1)); // [1]
10 }
11 }

  原始碼示例:

 1 // Arrays類
2 public static int[] copyOf(int[] original, int newLength) {
3 int[] copy = new int[newLength];
4 System.arraycopy(original, 0, copy, 0,
5 // 長度是舊陣列長度 與 新長度 取小
6 Math.min(original.length, newLength));
7 return copy;
8 }
9
10 // System類
11 public static native void arraycopy(Object src, int srcPos,
12 Object dest, int destPos,
13 int length);

  src:源陣列
  srcPos:源陣列要複製的起始位置
  dest:目的陣列
  destPos:目的陣列放置的起始位置
  length:複製的長度
  注意:src 和 dest都必須是同類型或者可以進行轉換型別的陣列。

5、equals()/deepEquals()方法

  ①、equals
  用於比較兩個陣列中對應位置的每一個元素是否相等。
  原始碼示例:

 1 // 基本資料型別陣列比較
2 public static boolean equals(int[] a, int[] a2) {
3 // 引用相等,則相同
4 if (a==a2)
5 return true;
6 if (a==null || a2==null)
7 return false;
8
9 int length = a.length;
10 // 長度不同,則不相同
11 if (a2.length != length)
12 return false;
13
14 // 迴圈依次比較陣列中每個元素是否相等
15 for (int i=0; i<length; i++)
16 if (a[i] != a2[i])
17 return false;
18
19 return true;
20 }
21
22 // 引用型別陣列比較
23 public static boolean equals(Object[] a, Object[] a2) {
24 if (a==a2)
25 return true;
26 if (a==null || a2==null)
27 return false;
28
29 int length = a.length;
30 if (a2.length != length)
31 return false;
32
33 for (int i=0; i<length; i++) {
34 Object o1 = a[i];
35 Object o2 = a2[i];
36
37 // 物件相同通過 equals 方法判斷
38 if (!(o1==null ? o2==null : o1.equals(o2)))
39 return false;
40 }
41
42 return true;
43 }

  ②、deepEquals
  比較兩個陣列的元素是否相等,可以巢狀任意層次的陣列。
  原始碼就是遞迴的使用 deepEquals 判斷每一層的陣列是否相同。
  程式碼示例:

1 public class Main {
2 public static void main(String[] args) {
3 String[][] name1 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}};
4 String[][] name2 = {{"G", "a", "o"}, {"H", "u", "a", "n"}, {"j", "i", "e"}};
5
6 System.out.println(Arrays.equals(name1, name2));// false
7 System.out.println(Arrays.deepEquals(name1, name2));// true
8 }
9 }

6、fill()方法

  該系列方法用於給陣列賦值,並能指定某個範圍賦值。
  程式碼示例:

1 public class Main {
2 public static void main(String[] args) {
3 int[] arr = new int[4];
4 System.out.println(Arrays.toString(arr)); // [0, 0, 0, 0]
5
6 Arrays.fill(arr, 6);
7 System.out.println(Arrays.toString(arr)); // [6, 6, 6, 6]
8 }
9 }

  原始碼示例:

 1 // 不寫註釋也能看懂的程式碼
2 public static void fill(int[] a, int val) {
3 for (int i = 0, len = a.length; i < len; i++)
4 a[i] = val;
5 }
6
7 public static void fill(int[] a, int fromIndex, int toIndex, int val) {
8 rangeCheck(a.length, fromIndex, toIndex);
9 for (int i = fromIndex; i < toIndex; i++)
10 a[i] = val;
11 }

7、toString 和 deepToString方法

  toString 用來列印一維陣列的元素,而 deepToString 用來列印多層次巢狀的陣列元素。

  參考文件:https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html