參考筆記:
Java中Arrays類(操作數組的工具)_java arrays-CSDN博客
Java——Arrays 類詳解_java arrays類-CSDN博客
目錄
1.Arrays類簡介
2.Arrays.toString
2.1 使用示例
2.2 源碼
3. Arrays.copyOf?
3.1 使用示例
3.2 源碼
4.Arrays.sort
4.1 默認排序使用示例
4.2?定制排序使用實例
4.3 Arrays.sort使用的算法
5.Arrays.binarySearch
5.1 使用示例
5.2 源碼
6.Arrays.fill
6.1 使用示例
6.2 源碼
7. Arrays.equals
7.1 使用案例
7.2 源碼
8. Arrays.deepEquals
9.Arrays.asList
9.1 使用細節和案例
1.Arrays類簡介
①?Arrays 類是 Java 語言中用于操作數組的一個工具類,提供了多種靜態方法來處理數組,包括排序、搜索、填充、比較等操作
②?Arrays 類位于 java.util.Arrays 中,該類所有的構造方法被設置為 private ,因此無法創建 Arrays 對象
③ Arrays 所有方法都是靜態的,可以直接通過 "Arrays.方法" 調用
2.Arrays.toString
Arrays.toString(...):返回任何類型數組的字符串形式
2.1 使用示例
import java.util.Arrays;
public class demo {public static void main(String[] args) {int[] arr = {1,2,3};System.out.println(Arrays.toString(arr));}
}
運行結果:
2.2 源碼
底層是重載了多個 toString 方法,這里以 String toString(int[ ] a) 為例
public static String toString(int[] a) {if (a == null){//判斷數組a是否為空,為空則返回字符串"null"return "null";}int iMax = a.length - 1;//數組a的最后一個元素索引if (iMax == -1){//如果iMax == -1,說明數組a的長度為0return "[]";}StringBuilder b = new StringBuilder();b.append('[');for (int i = 0; ; i++) {b.append(a[i]);//依次將數組的元素追加到字符串中if (i == iMax){//判斷是否為最終一個元素,如果是最后一個元素,則返回最終的字符串return b.append(']').toString();}b.append(", ");}
}
3. Arrays.copyOf?
Arrays.copyOf(type[ ] original,int newLength):拷貝任意類型數組,返回值是要拷貝的那個數組類型
original:??原數組
newLength:?指定新數組的長度
補充:也可以理解為從原數組 original 中復制 newLength 個元素到新數組中,如果 newLength 大于原數組的大小,則新數組中大于原數組大小的部分的元素都是類型默認值
3.1 使用示例
import java.util.Arrays;
public class demo {public static void main(String[] args) {int[] arr1 = {1,2,3,4};int arr1_len = arr1.length;int[] tmp1 = Arrays.copyOf(arr1,arr1_len); //指定tmp1數組的長度為arr1_len,并拷貝array數組并賦值到tmp1數組上System.out.println(tmp1.length);System.out.println(Arrays.toString(tmp1)); //打印tmp1數組,[1,2,3,4]System.out.println("-----------------------------");int[] arr2 = {4,5,6,7};int arr2_len = arr2.length;int[] tmp2 = Arrays.copyOf(arr2,2 * arr2_len); //指定tmp2數組的長度為2 * arr2_len,并拷貝array數組并賦值到tmp2數組上,System.out.println(tmp2.length);System.out.println(Arrays.toString(tmp2)); //打印tmp2數組,[4,5,6,7,0,0,0,0]System.out.println("-----------------------------");int[] arr3 = {9,10,11,12};int[] tmp3 = Arrays.copyOf(arr3,2);//指定tmp3數組的長度為2,則只會拷貝array數組的前2個元素到tmp3數組上System.out.println(tmp3.length);System.out.println(Arrays.toString(tmp3));//打印tmp3數組,[9,10]}
}
3.2 源碼
4.Arrays.sort
注:學 Arrays.sort 之前,最好先學一下關于 Comparable、Comparator 接口,可以看到我寫的另外一篇博客:【Java SE】Java比較器:Comparable、Comparator-CSDN博客
默認排序規則:
????????String:按照字符串中字符的 ASCII 值進行比較
????????Character:按照字符的 ASCII 值來進行比較
????????數值類型對應的包裝類以及 BigInteger、BigDecimal :按照它們對應的數值大小進行比較
????????Boolean:true 對應的包裝類實例大于 false 對應的包裝類實例
????????Date、Time等:后面的日期時間比前面的日期時間大
① Arrays.sort(type[ ] a):對整個 a 數組進行默認排序
② Arrays.sort(type[ ] a,int fromIndex,int toIndex):對 a 數組索引在 [fromIndex,toIndex) 的元素進行默認排序
③ Arrays.sort( T[ ]? a,Comparator <? super T> c):指定比較器 Comparator,對整個 a 數組進行定制排序
④ Arrays.sort( T[ ]? a,int fromIndex,int toIndex,Comparator <? super T> c):指定比較器 Comparator,對 a 數組索引在 [fromIndex,toIndex) 的元素進行定制排序
4.1 默認排序使用示例
import java.util.Arrays;
public class demo {public static void main(String[] args) {//1:Arrays.sort(type[ ] a):int[] arr1 = {-1,10,300,4};Arrays.sort(arr1);//從小到大排序System.out.println(Arrays.toString(arr1));//[-1,4,10,300]//2:Arrays.sort(type[ ] a,int fromIndex,int toIndex):int[] arr2 = {100,10,5,1};Arrays.sort(arr2,0,2);System.out.println(Arrays.toString(arr2));//[10,100,5,1]}
}
4.2?定制排序使用實例
import java.util.Arrays;
import java.util.Comparator;public class demo {public static void main(String[] args) {//方式1.使用匿名內部類傳入比較器 Comparator 接口Integer[] arr = {-1,100,4444,23};System.out.println("arr降序排序前:"+Arrays.toString(arr));//對arr實現降序排序Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {if(o1 > o2){return -1;//返回任何小于0的整數都可以}return 1;//返回任何大于0的整數都可以}});System.out.println("arr降序排序后:"+Arrays.toString(arr));//[4444,100,23,-1]System.out.println("--------------------------------");//方式2.定制比較器類實現 Comparator 接口StudentAgeComparator sc = new StudentAgeComparator();Student s1 = new Student("小馬", 55);Student s2 = new Student("蔡徐坤", 24);Student s3 = new Student("ftt", 17);Student s4 = new Student("jack", 30);Student[] personList = {s1,s2,s3,s4};System.out.println("personList按年齡降序排序前:");Arrays.stream(personList).forEach(student -> System.out.println(student));//對personList數組按對象的年齡降序排序Arrays.sort(personList,sc);System.out.println("personList按年齡降序排序后:");Arrays.stream(personList).forEach(student -> System.out.println(student));}
}//定制比較器類,按學生的年齡降序排序
class StudentAgeComparator implements Comparator<Student>{@Overridepublic int compare(Student s1, Student s2) {if (s1.age > s2.age){return -1;}else if (s1.age < s2.age){return 1;}else {return 0;}}
}class Student{public String name;public int age;public Student(){}public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
運行結果
Debug追溯
這里以上面的代碼?Debug 一下看看 Arrays.sort 底層是如何用到我們指定的比較器 Comparator 來進行排序的,如下 GIF 所示:
可以看到,Arrays.sort 底層最終會調用?TimSort 類的 binarySort 方法,該方法中,
if (c.compare(pivot, a[mid]) < 0)right = mid;
c 即為我們傳入的比較器 StudentAgeComparator
4.3 Arrays.sort使用的算法
①?基本類型數組(如 int[ ], char[ ] 等):
對于基本數據類型數組,Arrays.sort( ) 方法使用了一種名為 Dual-Pivot Quicksort 的排序算法這是一種改進的快速排序算法,由 Vladimir Yaroslavskiy 提出。它在平均情況下具有 O(n log n) 的時間復雜度,在實踐中通常表現良好
② 引用類型數組(如 Integer[ ], String[ ] 等):
對于引用類型數組,Arrays.sort( ) 方法則使用 Timsort 算法。這是一種混合排序算法,結合了歸并排序和插入排序的優點。Timsort 是為了優化對部分有序數據的排序而設計的,具有 O(n log n) 的時間復雜度,在實際應用中表現出色
5.Arrays.binarySearch
Arrays.binarySearch為二分查找算法。在已排序的數組中查找指定的某個元素,返回在數組中的索引
① Arrays.binarySearch(type[ ] a,type key):在整個數組 a 中查找元素 key,返回其索引。未找到時返回的是一個特定的負數,為?- (low + 1)?
② Arrays.binarySearch(type[ ] a,int fromIndex,int toIndex,type key):在數組 a 索引為[fromIndex,toIndex) 的元素中查找元素 key,返回其索引
5.1 使用示例
import java.util.Arrays;
public class demo {public static void main(String[] args) {int[] arr1 = {11, 22, 33, 44};int index1 = Arrays.binarySearch(arr1, 44);System.out.println("index of 44: " + index1);//3int[] arr2 = {11, 22, 33, 44};int index2 = Arrays.binarySearch(arr2,0,1,44);System.out.println("index of 44: " + index2);//返回的是一個負數,在[0,1)區間沒找到44}
}
5.2 源碼
流程圖
?binarySearch0源碼
binarySearch0 就是傳統的二分查找算法,比較簡單
private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {int low = fromIndex;//左邊界int high = toIndex - 1;//右邊界面while (low <= high) {int mid = (low + high) >>> 1;//相當于mid = (low + high) / 2int midVal = a[mid];//中間元素值if (midVal < key)low = mid + 1;else if (midVal > key)high = mid - 1;elsereturn mid;}return -(low + 1); // 沒有找到不是直接返回負一,返回一個特定的負數
}
6.Arrays.fill
① Arrays.fill (type[ ] a,type val):將 a 數組中的所有元素賦值為 val?
②?Arrays.fill (type[ ] a,int fromIndex,int toIndex,type val):將 a 數組中索引為?[fromIndex,toIndex) 的元素賦值為 val?
6.1 使用示例
import java.util.Arrays;
public class demo {public static void main(String[] args) {//1:Arrays.fill (type[ ] a,type val):將a數組中的所有元素賦值為valint[] arr = new int[10];Arrays.fill(arr, 5);Arrays.stream(arr).forEach(i -> System.out.print(i + " "));System.out.println();System.out.println("-------------------");//2:Arrays.fill (type[ ] a,int fromIndex,int toIndex,type val):將a數組中索引為[fromIndex,toIndex)的元素賦值為valArrays.fill(arr,0,5,4);Arrays.stream(arr).forEach(i -> System.out.print(i + " "));}
}
6.2 源碼
public static void fill(int[] a, int val) {for (int i = 0, len = a.length; i < len; i++)a[i] = 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. Arrays.equals
Arrays.equals (type[ ] a,type[ ]?a2):返回值為 boolean ;判斷一維數組 a 與 一維數組 a2 的內容是否完全相同,兩個數組的 type 需要一致
7.1 使用案例
import java.util.Arrays;
public class demo {public static void main(String[] args) {int[] arr1 = {1,2,3,4};int[] arr2 = {1,2,3,4};int[] arr3 = {100,99};System.out.println(Arrays.equals(arr1, arr2));//trueSystem.out.println(Arrays.equals(arr1, arr3));//false}
}
7.2 源碼
public static boolean equals(int[] a, int[] a2) {if (a==a2)//地址相同,內容一定相同return true;if (a==null || a2==null)//如果有一個為空,則返回falsereturn false;int length = a.length;if (a2.length != length)//長度不同,則返回falsereturn false;for (int i=0; i<length; i++)//逐個比較if (a[i] != a2[i])return false;return true;
}
8. Arrays.deepEquals
Arrays.deepEquals(Object[ ] a1,Object[ ] a2) :用于比較兩個多維數組 a1、a2 的內容是否完全相同
使用案例
import java.util.Arrays;public class demo {public static void main(String[] args) {int[][] array1 = {{1, 2, 3}, {4, 5, 6}};int[][] array2 = {{1, 2, 3}, {4, 5, 6}};int[][] array3 = {{1, 2, 3}, {4, 5, 7}};// 比較相同的二維數組boolean isEqual1 = Arrays.deepEquals(array1, array2);System.out.println("array1 和 array2 相等? " + isEqual1); // 輸出: true// 比較不同的二維數組boolean isEqual2 = Arrays.deepEquals(array1, array3);System.out.println("array1 和 array3 相等? " + isEqual2); // 輸出: false}
}
9.Arrays.asList
Arrays.asList( ) 方法是 Arrays 類的一個靜態方法。它可以將傳入的數據轉換為一個固定大小的列表 List
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}
9.1 使用細節和案例
① 形參是 (T.. a) 表示可以接收 0 個或者多個類型為 T(String、八大包裝類型、自定義類型) 的參數,編譯器會將傳入的實參轉換為T[ ] a?數組,當然也可以直接傳入一個 T[ ] 數組
② 返回的 List 的運行類型是 java.util.Arrays.ArrayList,是 Arrays 類的一個內部類,并不是平時經常使用的 java.util.ArrayList。這里要注意區分,很容易弄混
驗證
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class demo {public static void main(String[] args) {//1:傳入多個數據List<String> list1 = Arrays.asList("小馬","唱跳rap籃球");//2:直接傳入數組Integer[] arr1 = {1,2,3};List<Integer> list2 = Arrays.asList(arr1);System.out.println("list1的運行類型:" + list1.getClass());System.out.println("list2的運行類型:" + list2.getClass());//這里new的是java.util.ArrayListList<Object> list3 = new ArrayList<>();System.out.println("list3的運行類型:" + list3.getClass());}
}
運行結果:
③ 返回的 List 不是一個全新的獨立集合,而是對原始數組的包裝視圖:Wrapper View ,具體來說:
-
共享存儲空間:
-
返回的 List 直接引用原數組的內存地址
-
修改 List 中的元素 = 直接修改數組對應位置的元素,反之亦然
-
-
固定大小特性
-
由于數組長度不可變,因此返回的 List 會禁止結構性修改,比如不能使用 add 和 remove 來增加或刪除元素,這與 java.util.ArrayList 是完全不一樣的
-
驗證:共享存儲空間
import java.util.Arrays;
import java.util.List;public class demo {public static void main(String[] args) {Integer[] arr = {1, 2, 3, 4, 5};//轉換為列表List<Integer> list = Arrays.asList(arr);//修改列表中的元素list.set(0, 10);//打印修改后的列表和數組System.out.println("執行:list.set(0,10)");System.out.println("執行后的列表list: " + list); // 輸出: 修改后的列表: [10, 2, 3, 4, 5]System.out.println("執行后的數組arr: " + Arrays.toString(arr)); // 輸出: 修改后的數組: [10, 2, 3, 4, 5]System.out.println("------------------------------------------------");//修改數組中的元素arr[1] = 999;//打印修改后的列表和數組System.out.println("執行:arr[1] = 999");System.out.println("執行的列表list: " + list); // 輸出: 修改后的列表: [10, 999, 3, 4, 5]System.out.println("執行后的數組arr: " + Arrays.toString(arr)); // 輸出: 修改后的數組: [10, 999, 3, 4, 5]}
}
運行結果:?
驗證:固定大小特性,即不能使用 add 和 remove,編譯可以通過,但會報異常
從控制臺的異常信息可以看到,調用的是父類 AbstractList .add 方法,這里溯源一下,如下圖:
父類 AbstractList 的 add 方法只是簡單的 throw 一個異常,因此在使用 add 方法時會發生異常。 remove 方法也是類似,這里就不再贅述了