0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JDK中java.lang.Arrays 類的源碼解析

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-11 15:31 ? 次閱讀

日常開發(fā)中,我們會使用各種工具類,利用封裝好的輪子,能讓我們的開發(fā)事半功倍。但是在JDK中,有一個特別的工具類——java.lang.Arrays.class,其源碼實現(xiàn)還是挺精湛,接下來讓我們來揭開它神秘的面紗。

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

1、asList

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

作用是返回由指定數(shù)組支持的固定大小列表。

注意 :這個方法返回的 ArrayList 不是我們常用的集合類 java.util.ArrayList。這里的 ArrayList 是 Arrays 的一個內(nèi)部類 java.util.Arrays.ArrayList。這個內(nèi)部類有如下屬性和方法:
圖片

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) {
            if (array==null){
                throw new NullPointerException();
            }
            a = array;
        }

        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) {
            if (o==null) {
                for (int i=0; i< a.length; i++){
                    if (a[i]==null){
                        return i;
                    }
                }
            } else {
                for (int i=0; i< a.length; i++){
                    if (o.equals(a[i])){
                        return i;
                    }
                }
            }
            return -1;
        }

        public boolean contains(Object o) {
            return indexOf(o) != -1;
        }
}

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

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

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

圖片

②、引用類型的數(shù)組和基本類型的數(shù)組區(qū)別

String[] str = {"a","b","c"};
List listStr = Arrays.asList(str);
System.out.println(listStr.size());//3

int[] i = {1,2,3};
List listI = Arrays.asList(i);
System.out.println(listI.size());//1

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

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

所以將上面的方法泛型化補全應(yīng)該是:

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

int[] i = {1,2,3};
List< int[] > listI = Arrays.asList(i);//注意這里L(fēng)ist參數(shù)為 int[] ,而不是 int
System.out.println(listI.size());//1

Integer[] in = {1,2,3};
List< Integer > listIn = Arrays.asList(in);//這里參數(shù)為int的包裝類Integer,所以集合長度為3
System.out.println(listIn.size());//3

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

String[] str = {"a","b","c"};
List< String > listStr = Arrays.asList(str);
//執(zhí)行更新操作前
System.out.println(Arrays.toString(str));//[a, b, c]
listStr.set(0, "d");//將第一個元素a改為d
//執(zhí)行更新操作后
System.out.println(Arrays.toString(str));//[d, b, c]

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

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

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

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

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

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

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

2、sort

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

①、基本類型的數(shù)組

這里我們以 int[ ] 為例看看:

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

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

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

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

②、對象類型數(shù)組

該類型的數(shù)組進行排序可以實現(xiàn) Comparable 接口,重寫 compareTo 方法進行排序。

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

String 類型實現(xiàn)了 Comparable 接口,內(nèi)部的 compareTo 方法是按照字典碼進行比較的。

③、沒有實現(xiàn)Comparable接口的,可以通過Comparator實現(xiàn)排序

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

3、binarySearch

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

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

實例:

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

具體源碼實現(xiàn):

public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }
    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;//取中間值下標
            int midVal = a[mid];//取中間值
            
            if (midVal < key){
                low = mid + 1;
                else if (midVal > key)
                high = mid - 1;
            }
            else{
                return mid; 
            }
        }
        return -(low + 1); 
}

4、copyOf

拷貝數(shù)組元素。底層采用 System.arraycopy() 實現(xiàn),這是一個native方法。

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

src:源數(shù)組

srcPos:源數(shù)組要復(fù)制的起始位置

dest:目的數(shù)組

destPos:目的數(shù)組放置的起始位置

length:復(fù)制的長度

注意:src 和 dest都必須是同類型或者可以進行轉(zhuǎn)換類型的數(shù)組。

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 源數(shù)組
     * @param newLength //返回新數(shù)組的長度
     * @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、fill

該系列方法用于給數(shù)組賦值,并能指定某個范圍賦值。

//給a數(shù)組所有元素賦值 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結(jié)尾的下標都賦值 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;
        }
    }

6、toString 和 deepToString

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

public static String toString(int[] a) {
        if (a == null){
            return "null";
        }
        int iMax = a.length - 1;
        if (iMax == -1){
            return "[]";
        }

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(a[i]);
            if (i == iMax){
                return b.append(']').toString();
            }
            b.append(", ");
        }
    }

7、小結(jié)

好了,這就是JDK中java.lang.Arrays 類的源碼解析。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2946

    瀏覽量

    104368
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    630

    瀏覽量

    29074
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    411

    瀏覽量

    25858
  • JDK
    JDK
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    16563
收藏 人收藏

    評論

    相關(guān)推薦

    JDK的安裝、環(huán)境配置及使用

    ,變量值輸入庫名C:\jdk1.5\lib\dt.jar;C:\jdk1.5\lib\tools.jar;然后選擇確定。再次選擇“系統(tǒng)變量”的“新建”,在變量名
    發(fā)表于 12-06 00:19

    java jdk安裝參考步驟

    1、把jdk-8u5-linux-x64.gz解壓,然后把解壓的文件夾放到/usr/lib/jvm/下,并重命名為jdk,這個目錄可以自定義。2、編輯~/.basrc文件,在文件的末尾追加下面的命令
    發(fā)表于 09-25 16:43

    JAVAJDK、J2EE、J2SE、J2ME的概念詳解

    開發(fā)工具包,基本上每個學(xué)java的人都會先在機器上裝一個JDK,那他都包含哪幾部分呢?讓我們看一下JDK的安裝目錄。在目錄下面有六個文件夾、一個src
    發(fā)表于 07-10 08:28

    加載機制的過程和策略

    java.lang,在使用引導(dǎo)加載器加載時會先加載JDK的String,因為這個本來是屬
    發(fā)表于 01-05 17:21

    樹莓派如何安裝Java JDK?

    。Oracle Java 具有其他一些商業(yè)功能,并且許可僅允許非商業(yè)用途。下面介紹如何在樹莓派的 Raspbian OS 上安裝Java(OpenJDK)?! ∵\行以下命令安裝最新的 JDK 版本,目前
    發(fā)表于 02-02 16:37

    java jdk6.0官方下載

    java jdk6.0下載如何件: java jdk6.0安裝步驟: 第一步 JDK1.6的安裝步驟 第一步雙擊安裝文件
    發(fā)表于 10-17 11:47 ?155次下載
    <b class='flag-5'>java</b> <b class='flag-5'>jdk</b>6.0官方下載

    深入理解java枚舉類型enum用法

    enum 的全稱為 enumeration, 是 JDK 1.5 引入的新特性,存放在 java.lang。 下面是我在使用 enum 過程
    發(fā)表于 09-27 11:49 ?0次下載

    理解Java字符流與字節(jié)流的區(qū)別

    JDK稱為Java開發(fā)包或Java開發(fā)工具,是一個編寫Java的Applet小程序和應(yīng)用程序的程序開發(fā)環(huán)境。JDK是整個
    發(fā)表于 12-04 10:39 ?1095次閱讀
    理解<b class='flag-5'>Java</b><b class='flag-5'>中</b>字符流與字節(jié)流的區(qū)別

    基于java的負載均衡算法解析源碼分享

    負載均衡的算法實際上就是解決跨系統(tǒng)調(diào)用的時候,在考慮后端機器承載情況的前提下,保證請求分配的平衡和合理。下面是基于java的負載均衡算法解析源碼,以供參考。
    發(fā)表于 01-01 19:29 ?2189次閱讀

    Java數(shù)組的常用方法_Java:數(shù)組工具Arrays的常用方法的用法及代碼

    本文主要詳細介紹了Java數(shù)組的常用方法以及數(shù)組工具Arrays的常用方法的用法及代碼。
    發(fā)表于 01-29 10:25 ?2898次閱讀

    基于JDK 1.8來分析Thread源碼

    由上圖我們可以看出,Thread實現(xiàn)了Runnable接口,而Runnable在JDK 1.8被@FunctionalInterface注解標記為函數(shù)式接口,Runnable接口在JDK
    的頭像 發(fā)表于 02-06 17:12 ?564次閱讀

    JavaArrays是什么 Arrays常用方法

    了解Arrays的概念 **A****rrays** 位于java.util包下,Arrays是一個操作數(shù)組的工具。
    的頭像 發(fā)表于 02-17 15:11 ?985次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中</b><b class='flag-5'>Arrays</b><b class='flag-5'>類</b>是什么 <b class='flag-5'>Arrays</b>常用方法

    怎樣運用Java實現(xiàn)冒泡排序和Arrays排序出來

    在數(shù)據(jù)結(jié)構(gòu)我們學(xué)習(xí)了解了冒泡排序和Arrays排序的基本算法,但沒能夠用編程語言實現(xiàn)出來。那我們應(yīng)該怎樣運用Java通過編程語言將冒泡排序和Arrays排序?qū)崿F(xiàn)出來呢?
    的頭像 發(fā)表于 03-02 09:37 ?462次閱讀
    怎樣運用<b class='flag-5'>Java</b>實現(xiàn)冒泡排序和<b class='flag-5'>Arrays</b>排序出來

    JDKjava.lang.String 源碼解析

    1、String 的定義 public final class String implements java.io.Serializable, Comparable, CharSequence
    的頭像 發(fā)表于 10-13 10:51 ?423次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java.lang</b>.String <b class='flag-5'>類</b>的<b class='flag-5'>源碼</b><b class='flag-5'>解析</b>

    weblogic修改jdk路徑

    WebLogic是一個流行的Java應(yīng)用服務(wù)器,可以用于部署和管理企業(yè)級Java應(yīng)用程序。在WebLogic的安裝和配置過程,我們可能會遇到需要修改JDK
    的頭像 發(fā)表于 12-05 14:46 ?1134次閱讀