JDK1.8源碼(四)——java.util.Arrays 類

目錄

 


  java.util.Arrays 類是 JDK 提供的一個工具類,用來處理數組的各種方法,而且每個方法基本上都是靜態方法,能直接通過類名Arrays調用。

回到頂部

1、asList

    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

  作用是返回由指定數組支持的固定大小列表

  注意:這個方法返回的 ArrayList 不是我們常用的集合類 java.util.ArrayList。這裏的 ArrayList 是 Arrays 的一個內部類 java.util.Arrays.ArrayList。這個內部類有如下屬性和方法:

  

複製代碼

 1     private static class ArrayList<E> extends AbstractList<E>
 2         implements RandomAccess, java.io.Serializable
 3     {
 4         private static final long serialVersionUID = -2764017481108945198L;
 5         private final E[] a;
 6 
 7         ArrayList(E[] array) {
 8             if (array==null)
 9                 throw new NullPointerException();
10             a = array;
11         }
12 
13         public int size() {
14             return a.length;
15         }
16 
17         public Object[] toArray() {
18             return a.clone();
19         }
20 
21         public <T> T[] toArray(T[] a) {
22             int size = size();
23             if (a.length < size)
24                 return Arrays.copyOf(this.a, size,
25                                      (Class<? extends T[]>) a.getClass());
26             System.arraycopy(this.a, 0, a, 0, size);
27             if (a.length > size)
28                 a[size] = null;
29             return a;
30         }
31 
32         public E get(int index) {
33             return a[index];
34         }
35 
36         public E set(int index, E element) {
37             E oldValue = a[index];
38             a[index] = element;
39             return oldValue;
40         }
41 
42         public int indexOf(Object o) {
43             if (o==null) {
44                 for (int i=0; i<a.length; i++)
45                     if (a[i]==null)
46                         return i;
47             } else {
48                 for (int i=0; i<a.length; i++)
49                     if (o.equals(a[i]))
50                         return i;
51             }
52             return -1;
53         }
54 
55         public boolean contains(Object o) {
56             return indexOf(o) != -1;
57         }
58     }

複製代碼

  ①、返回的 ArrayList 數組是一個定長列表,我們只能對其進行查看或者修改,但是不能進行添加或者刪除操作

  通過源碼我們發現該類是沒有add()或者remove() 這樣的方法的,如果對其進行增加或者刪除操作,都會調用其父類 AbstractList 對應的方法,而追溯父類的方法最終會拋出 UnsupportedOperationException 異常。如下:

1 String[] str = {"a","b","c"};
2 List<String> listStr = Arrays.asList(str);
3 listStr.set(1, "e");//可以進行修改
4 System.out.println(listStr.toString());//[a, e, c]
5 listStr.add("a");//添加元素會報錯 java.lang.UnsupportedOperationException 

  

  ②、引用類型的數組和基本類型的數組區別

複製代碼

1 String[] str = {"a","b","c"};
2 List listStr = Arrays.asList(str);
3 System.out.println(listStr.size());//3
4 
5 int[] i = {1,2,3};
6 List listI = Arrays.asList(i);
7 System.out.println(listI.size());//1

複製代碼

  上面的結果第一個listStr.size()==3,而第二個 listI.size()==1。這是爲什麼呢?

  我們看源碼,在 Arrays.asList 中,方法聲明爲  <T> List<T> asList(T... a)。該方法接收一個可變參數,並且這個可變參數類型是作爲泛型的參數。我們知道基本數據類型是不能作爲泛型的參數的,但是數組是引用類型,所以數組是可以泛型化的,於是 int[] 作爲了整個參數類型,而不是 int 作爲參數類型。

  所以將上面的方法泛型化補全應該是:

複製代碼

 1 String[] str = {"a","b","c"};
 2 List<String> listStr = Arrays.asList(str);
 3 System.out.println(listStr.size());//3
 4 
 5 int[] i = {1,2,3};
 6 List<int[]> listI = Arrays.asList(i);//注意這裏List參數爲 int[] ,而不是 int
 7 System.out.println(listI.size());//1
 8 
 9 Integer[] in = {1,2,3};
10 List<Integer> listIn = Arrays.asList(in);//這裏參數爲int的包裝類Integer,所以集合長度爲3
11 System.out.println(listIn.size());//3

複製代碼

  ③、返回的列表ArrayList裏面的元素都是引用,不是獨立出來的對象

複製代碼

1 String[] str = {"a","b","c"};
2 List<String> listStr = Arrays.asList(str);
3 //執行更新操作前
4 System.out.println(Arrays.toString(str));//[a, b, c]
5 listStr.set(0, "d");//將第一個元素a改爲d
6 //執行更新操作後
7 System.out.println(Arrays.toString(str));//[d, b, c]

複製代碼

  這裏的Arrays.toString()方法就是打印數組的內容,後面會介紹。我們看修改集合的內容,原數組的內容也變化了,所以這裏傳入的是引用類型。

  ④、已知數組數據,如何快速獲取一個可進行增刪改查的列表List?

1 String[] str = {"a","b","c"};
2 List<String> listStr = new ArrayList<>(Arrays.asList(str));
3 listStr.add("d");
4 System.out.println(listStr.size());//4

  這裏的ArrayList 集合類後面我們會詳細講解,大家目前只需要知道有這種用法即可。

  ⑤、Arrays.asList() 方法使用場景

  Arrays工具類提供了一個方法asList, 使用該方法可以將一個變長參數或者數組轉換成List 。但是,生成的List的長度是固定的;能夠進行修改操作(比如,修改某個位置的元素);不能執行影響長度的操作(如add、remove等操作),否則會拋出UnsupportedOperationException異常。

  所以 Arrays.asList 比較適合那些已經有數組數據或者一些元素,而需要快速構建一個List,只用於讀取操作,而不進行添加或刪除操作的場景。

回到頂部

2、sort

  該方法是用於數組排序,在 Arrays 類中有該方法的一系列重載方法,能對7種基本數據類型,包括 byte,char,double,float,int,long,short 等都能進行排序,還有 Object 類型(實現了Comparable接口),以及比較器 Comparator 。

  

  ①、基本類型的數組

  這裏我們以 int[ ] 爲例看看:

1 int[] num = {1,3,8,5,2,4,6,7};
2 Arrays.sort(num);
3 System.out.println(Arrays.toString(num));//[1, 2, 3, 4, 5, 6, 7, 8]

  通過調用 sort(int[] a) 方法,將原數組按照升序的順序排列。下面我們通過源碼看看是如何實現排序的:

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

  在 Arrays.sort 方法內部調用 DualPivotQuicksort.sort 方法,這個方法的源碼很長,分別對於數組的長度進行了各種算法的劃分,包括快速排序,插入排序,冒泡排序都有使用。詳細源碼可以參考這篇博客

  ②、對象類型數組

  該類型的數組進行排序可以實現 Comparable 接口,重寫 compareTo 方法進行排序。

1 String[] str = {"a","f","c","d"};
2 Arrays.sort(str);
3 System.out.println(Arrays.toString(str));//[a, c, d, f]

  String 類型實現了 Comparable 接口,內部的 compareTo 方法是按照字典碼進行比較的。

  ③、沒有實現Comparable接口的,可以通過Comparator實現排序

複製代碼

 1 Person[] p = new Person[]{new Person("zhangsan",22),new Person("wangwu",11),new Person("lisi",33)};
 2 Arrays.sort(p,new Comparator<Person>() {
 3     @Override
 4     public int compare(Person o1, Person o2) {
 5         if(o1 == null || o2 == null){
 6             return 0;
 7         }
 8         return o1.getPage()-o2.getPage();
 9     }
10 });    
11 System.out.println(Arrays.toString(p));

複製代碼

回到頂部

3、binarySearch

  用二分法查找數組中的某個元素。該方法和 sort 方法一樣,適用於各種基本數據類型以及對象。

  注意:二分法是對以及有序的數組進行查找(比如先用Arrays.sort()進行排序,然後調用此方法進行查找)。找到元素返回下標,沒有則返回 -1

  實例:

1 int[] num = {1,3,8,5,2,4,6,7};
2 Arrays.sort(num);
3 System.out.println(Arrays.toString(num));//[1, 2, 3, 4, 5, 6, 7, 8]
4 System.out.println(Arrays.binarySearch(num, 2));//返回元素的下標 1

  具體源碼實現:

複製代碼

 1     public static int binarySearch(int[] a, int key) {
 2         return binarySearch0(a, 0, a.length, key);
 3     }
 4     private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {
 5         int low = fromIndex;
 6         int high = toIndex - 1;
 7         
 8         while (low <= high) {
 9             int mid = (low + high) >>> 1;//取中間值下標
10             int midVal = a[mid];//取中間值
11             
12             if (midVal < key)
13             low = mid + 1;
14             else if (midVal > key)
15             high = mid - 1;
16             else
17             return mid; 
18         }
19         return -(low + 1); 
20     }

複製代碼

回到頂部

4、copyOf

  拷貝數組元素。底層採用 System.arraycopy() 實現,這是一個native方法。

    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

  src:源數組

  srcPos:源數組要複製的起始位置

  dest:目的數組

  destPos:目的數組放置的起始位置

  length:複製的長度

  注意:src 和 dest都必須是同類型或者可以進行轉換類型的數組。

int[] num1 = {1,2,3};
int[] num2 = new int[3];
System.arraycopy(num1, 0, num2, 0, num1.length);
System.out.println(Arrays.toString(num2));//[1, 2, 3]

複製代碼

    /**
     * @param original 源數組
     * @param newLength //返回新數組的長度
     * @return
     */
    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

複製代碼

回到頂部

5、equals 和 deepEquals

  ①、equals

  equals 用來比較兩個數組中對應位置的每個元素是否相等。

  

  八種基本數據類型以及對象都能進行比較。

  我們先看看 int類型的數組比較源碼實現:

複製代碼

 1     public static boolean equals(int[] a, int[] a2) {
 2         if (a==a2)//數組引用相等,則裏面的元素一定相等
 3             return true;
 4         if (a==null || a2==null)//兩個數組其中一個爲null,都返回false
 5             return false;
 6 
 7         int length = a.length;
 8         if (a2.length != length)//兩個數組長度不等,返回false
 9             return false;
10 
11         for (int i=0; i<length; i++)//通過for循環依次比較數組中每個元素是否相等
12             if (a[i] != a2[i])
13                 return false;
14 
15         return true;
16     }

複製代碼

  在看對象數組的比較:

複製代碼

 1     public static boolean equals(Object[] a, Object[] a2) {
 2         if (a==a2)
 3             return true;
 4         if (a==null || a2==null)
 5             return false;
 6 
 7         int length = a.length;
 8         if (a2.length != length)
 9             return false;
10 
11         for (int i=0; i<length; i++) {
12             Object o1 = a[i];
13             Object o2 = a2[i];
14             if (!(o1==null ? o2==null : o1.equals(o2)))
15                 return false;
16         }
17 
18         return true;
19     }

複製代碼

  基本上也是通過 equals 來判斷。

  ②、deepEquals

  也是用來比較兩個數組的元素是否相等,不過 deepEquals 能夠進行比較多維數組,而且是任意層次的嵌套數組。

         String[][] name1 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}};  
         String[][] name2 = {{ "G","a","o" },{ "H","u","a","n"},{ "j","i","e"}};
         System.out.println(Arrays.equals(name1,name2));// false  
         System.out.println(Arrays.deepEquals(name1,name2));// true

回到頂部

6、fill

  該系列方法用於給數組賦值,並能指定某個範圍賦值。

複製代碼

    //給a數組所有元素賦值 val
    public static void fill(int[] a, int val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
    }
    
    //給從 fromIndex 開始的下標,toIndex-1結尾的下標都賦值 val,左閉右開
    public static void fill(int[] a, int fromIndex, int toIndex, int val) {
        rangeCheck(a.length, fromIndex, toIndex);//判斷範圍是否合理
        for (int i = fromIndex; i < toIndex; i++)
            a[i] = val;
    }

複製代碼

回到頂部

7、toString 和 deepToString

  toString 用來打印一維數組的元素,而 deepToString 用來打印多層次嵌套的數組元素。

複製代碼

 1     public static String toString(int[] a) {
 2         if (a == null)
 3             return "null";
 4         int iMax = a.length - 1;
 5         if (iMax == -1)
 6             return "[]";
 7 
 8         StringBuilder b = new StringBuilder();
 9         b.append('[');
10         for (int i = 0; ; i++) {
11             b.append(a[i]);
12             if (i == iMax)
13                 return b.append(']').toString();
14             b.append(", ");
15         }
16     }

複製代碼

 

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章