欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java數(shù)組擴容的三大小結(jié)

 更新時間:2023年08月14日 10:19:13   作者:白.都  
當(dāng)數(shù)組需要容納更多元素時,可以通過擴容來增加其容量,本文主要介紹了Java數(shù)組擴容的三大小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

方案1:新建數(shù)組

這種方法新建的數(shù)組必須要比原先的長度要長,然后將原來的數(shù)組內(nèi)容移到新的數(shù)組中

<!--more-->
int[] a = {1, 2, 3, 4, 5};
?
// 創(chuàng)建新數(shù)組,長度為源數(shù)組的兩倍
int[] b = new int[a.length * 2];
?
// 將舊數(shù)組內(nèi)容復(fù)制到新數(shù)組
for (int i = 0; i < a.length; i++) {
? ? b[i] = a[i];
}
?
// 新數(shù)組內(nèi)容賦值給源數(shù)組
a = b;
?
// 打印結(jié)果
System.out.println(Arrays.toString(a));

輸出結(jié)果

 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]

方案2:Arrays.copyOf

int[] a = {1, 2, 3, 4, 5};
?
// 第一個參數(shù)是拷貝的數(shù)組,第二個參數(shù)是擴容長度,且返回一個新數(shù)組
a = Arrays.copyOf(a, a.length * 2);
?
// 打印結(jié)果
System.out.println(Arrays.toString(a));

輸出結(jié)果

 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]

Arrays.copyof是用于數(shù)組進(jìn)行復(fù)制時常使用的方法,本身在Arrays類里面,而之所以能這么使用而不用創(chuàng)建對象在于該方法本身由static修飾,被static修飾的方法可以在該類創(chuàng)建對象前載入jvm。

public static long[] copyOf(long[] original, int newLength) {
    long[] copy = new long[newLength];
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}

通過上面的代碼可以看出,其本質(zhì)是調(diào)用了System.arraycopy方法。

先產(chǎn)生一個新的數(shù)組然后調(diào)用arraycopy方法最后在返回產(chǎn)生的新數(shù)組。但是我們進(jìn)行數(shù)組擴容的時候禪城了新數(shù)組,但是原數(shù)組依然存在,造成了內(nèi)存的浪費。

方案3:System.arraycopy

int[] a = {1, 2, 3, 4, 5};
?
// 定義新數(shù)組,長度為源數(shù)組的兩倍
int[] b = new int[a.length * 2];
?
/**
 * src      需要拷貝的源數(shù)組
 * srcPos   源數(shù)組中的起始位置
 * dest     目標(biāo)數(shù)組
 * destPos  目標(biāo)數(shù)組中的起始位置
 * length   要復(fù)制的數(shù)組元素數(shù)量
 */
System.arraycopy(a, 0, b, 0, a.length);
?
// 新數(shù)組內(nèi)容賦值給原數(shù)組
a = b;
?
// 打印結(jié)果
System.out.println(Arrays.toString(a));

輸出結(jié)果

 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]

arraycopy源碼

/**
     * @param src     the source array.  源數(shù)組
     * @param srcPos  starting position in the source array. 要復(fù)制的源數(shù)組的起始位置
     * @param dest    the destination array. 目標(biāo)數(shù)組
     * @param destPos starting position in the destination data. 目標(biāo)數(shù)組的起始位置
     * @param length  the number of array elements to be copied. 要復(fù)制的長度
     * @throws IndexOutOfBoundsException if copying would cause
     *                                   access of data outside array bounds.
     *                                   如果復(fù)制會導(dǎo)致數(shù)據(jù)的訪問超出數(shù)組邊界。
     *                                   則會報IndexOutOfBoundsException索引越界異常
     * @throws ArrayStoreException       if an element in the <code>src</code> array
     *                                   could not be stored into the 
                                         <code>dest</code> array
     *                                   because of a type mismatch.
     *                                   如果由于類型不匹配而無法將src數(shù)組中的元素存儲到dest數(shù)組中。
     *                                   則會報 ArrayStoreException數(shù)組存儲異常
     * @throws NullPointerException      if either <code>src</code> or
     *                                   <code>dest</code> is <code>null</code>.
     *                                   如果src或dest為null。
     *                                   則會報NullPointerException空指針異常
     */
?
    public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

System.arraycopy()的幾種常用方法(普通for循環(huán)和arraycopy方法對比)

1. 從舊數(shù)組拷貝到新數(shù)組

//從舊數(shù)組拷貝到新數(shù)組
for (int i=0;i<size;i++){
    arrayNew[i]=array[i];
}
System.arraycopy(array, 0, arrayNew, 0, array.length);

2. 從左向右循環(huán),逐個元素向左挪一位。

//從左向右循環(huán),逐個元素向左挪一位。
for (int i = index; i < size - 1; i++) {
    array[i] = array[i + 1];
}
System.arraycopy(array, index + 1, array, index, size - 1 - index);

3. 從右向左循環(huán),逐個元素向右挪一位。

//從右向左循環(huán),逐個元素向右挪一位。
for (int i = size - 1; i >= index; i--) {
    array[i + 1] = array[i];
}
System.arraycopy(array, index, array, index + 1, size - index);

System.arraycopy()深層理解

深復(fù)制還是淺復(fù)制

先說結(jié)論 :

  • 當(dāng)數(shù)組為一維數(shù)組,且元素為基本類型或String類型時,屬于深拷貝,即原數(shù)組與新數(shù)組的元素不會相互影響。
  • 當(dāng)數(shù)組為多維數(shù)組,或一維數(shù)組中的元素為引用類型時,屬于淺拷貝,原數(shù)組與新數(shù)組的元素引用指向同一個對象。

引用對象

構(gòu)建一個User類型源數(shù)組,復(fù)制后至target數(shù)組,比較第一個元素的內(nèi)存地址,判斷結(jié)果是相同的,證明為淺復(fù)制;后修改target數(shù)組數(shù)組的隨機元素,發(fā)現(xiàn)原來的值也變了。

public class SystemArrayCopyTestCase {
?
    public static void main(String[] args) {
        User[] users = new User[] { 
                new User(1), 
                new User(2),
                new User(3) };// 初始化對象數(shù)組
        User[] target = new User[users.length];// 新建一個目標(biāo)對象數(shù)組
        System.arraycopy(users, 0, target, 0, users.length);// 實現(xiàn)復(fù)制
        System.out.println("源對象與目標(biāo)對象的物理地址是否一樣:" + (users[0] == target[0] ? "淺復(fù)制" : "深復(fù)制"));  //淺復(fù)制
        target[0].setId(5);
        System.out.println("修改目標(biāo)對象的屬性值后源對象users:");
        for (User user : users) {
            System.out.println(user);
        }
    }
}
?
class User {
}
?

System.arraycopy() 在拷貝數(shù)組的時候,采用的使用潛復(fù)制,復(fù)制結(jié)果是一維的引用變量傳遞給新數(shù)組的一維數(shù)組,修改新數(shù)組時,會影響原來的數(shù)組。

一維數(shù)組和多維數(shù)組

將一維數(shù)組作源數(shù)組,進(jìn)行拷貝,產(chǎn)生target數(shù)組;然后修改target數(shù)組中的元素,新數(shù)組沒變,證明是值拷貝,修改新數(shù)組不會影響原來的值。

將多維數(shù)組作源數(shù)組,進(jìn)行拷貝至目標(biāo)數(shù)組,修改至目標(biāo)數(shù)組的元素,新數(shù)組也變了,說明是二者是相同的引用,而這時改變其中任何一個數(shù)組的元素的值,其實都修改了共同數(shù)組元素的值,所以原數(shù)組和新數(shù)組的元素值都一樣了

線程是否安全(摘自網(wǎng)絡(luò))

System.ayyaycopy是不安全的。

public class ArrayCopyThreadSafe {
    private static int[] arrayOriginal = new int[1024 * 1024 * 10];
    private static int[] arraySrc = new int[1024 * 1024 * 10];
    private static int[] arrayDist = new int[1024 * 1024 * 10];
    private static ReentrantLock lock = new ReentrantLock();
?
    private static void modify() {
        for (int i = 0; i < arraySrc.length; i++) {
            arraySrc[i] = i + 1;
        }
    }
?
    private static void copy() {
        System.arraycopy(arraySrc, 0, arrayDist, 0, arraySrc.length);
    }
?
    private static void init() {
        for (int i = 0; i < arraySrc.length; i++) {
            arrayOriginal[i] = i;
            arraySrc[i] = i;
            arrayDist[i] = 0;
        }
    }
?
    private static void doThreadSafeCheck() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("run count: " + (i + 1));
            init();
            Condition condition = lock.newCondition();
?
            new Thread(new Runnable() {
                @Override
                public void run() {
                    lock.lock();
                    condition.signalAll();
                    lock.unlock();
                    copy();
                }
            }).start();
?
?
            lock.lock();
            // 這里使用 Condition 來保證拷貝線程先已經(jīng)運行了.
            condition.await();
            lock.unlock();
?
            Thread.sleep(2); // 休眠2毫秒, 確??截惒僮饕呀?jīng)執(zhí)行了, 才執(zhí)行修改操作.
            modify();
?
            if (!Arrays.equals(arrayOriginal, arrayDist)) {
                throw new RuntimeException("System.arraycopy is not thread safe");
            }
        }
    }
?
    public static void main(String[] args) throws Exception {
        doThreadSafeCheck();
    }
}
?

這個例子的具體操作是:

arrayOriginal 和 arraySrc 初始化時是相同的, 而 arrayDist 是全為零的.

啟動一個線程運行 copy() 方法來拷貝 arraySrc 到 arrayDist 中.

在主線程執(zhí)行 modify() 操作, 修改 arraySrc 的內(nèi)容. 為了確保 copy() 操作先于 modify() 操作, 我使用 Condition, 并且延時了兩毫秒, 以此來保證執(zhí)行拷貝操作(即System.arraycopy) 先于修改操作.

根據(jù)第三點, 如果 System.arraycopy 是線程安全的, 那么先執(zhí)行拷貝操作, 再執(zhí)行修改操作時, 不會影響復(fù)制結(jié)果, 因此 arrayOriginal 必然等于 arrayDist; 而如果 System.arraycopy 是線程不安全的, 那么 arrayOriginal 不等于 arrayDist.

run count: 1
Exception in thread "main" java.lang.RuntimeException: System.arraycopy is not thread safe
    at ArrayCopyThreadSafe.doThreadSafeCheck(ArrayCopyThreadSafe.java:54)
    at ArrayCopyThreadSafe.main(ArrayCopyThreadSafe.java:60)

結(jié)論 :System.ayyaycopy是不安全的。

System.arraycopy()和for()相比誰更高效

當(dāng)測試數(shù)組的范圍比較小的時候,兩者相差的時間無幾,當(dāng)測試數(shù)組的長度達(dá)到百萬級別,System.arraycopy的速度優(yōu)勢就開始體現(xiàn)了,根據(jù)對底層的理解,System.arraycopy是對內(nèi)存直接進(jìn)行復(fù)制,減少了for循環(huán)過程中的尋址時間,從而提高了效能。

到此這篇關(guān)于Java數(shù)組擴容的三大小結(jié)的文章就介紹到這了,更多相關(guān)Java數(shù)組擴容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于maven install報錯原因揭秘:parent.relativePath指向錯誤的本地POM文件

    關(guān)于maven install報錯原因揭秘:parent.relativePath指向錯誤的本地POM文件

    在使用Maven進(jìn)行項目構(gòu)建時,如果遇到'parent.relativePath'指向錯誤的本地POM文件的問題,可能會導(dǎo)致構(gòu)建失敗,這通常是由于父項目POM文件的相對路徑設(shè)置錯誤、本地POM文件與父項目POM文件版本或內(nèi)容不一致所致,解決方法包括檢查并修正父項目POM文件中的相對路徑設(shè)置
    2024-09-09
  • tomcat請求流程源碼解進(jìn)階篇

    tomcat請求流程源碼解進(jìn)階篇

    這篇文章主要為大家介紹了tomcat請求流程源碼解進(jìn)階,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Java Thread之Sleep()使用方法及總結(jié)

    Java Thread之Sleep()使用方法及總結(jié)

    這篇文章主要介紹了Java Thread之Sleep()使用方法及總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Spring Boot如何防止重復(fù)提交

    Spring Boot如何防止重復(fù)提交

    這篇文章主要為大家詳細(xì)介紹了Spring Boot如何防止重復(fù)提交,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • HttpMessageConverter報文信息轉(zhuǎn)換器的深入講解

    HttpMessageConverter報文信息轉(zhuǎn)換器的深入講解

    在Spring中內(nèi)置了大量的HttpMessageConverter,通過請求頭信息中的MIME類型,選擇相應(yīng)的HttpMessageConverter,這篇文章主要給大家介紹了關(guān)于HttpMessageConverter報文信息轉(zhuǎn)換器的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • 淺析Java中如何實現(xiàn)線程之間通信

    淺析Java中如何實現(xiàn)線程之間通信

    本篇文章主要介紹了淺析Java中如何實現(xiàn)線程之間通信。針對 Java 的線程間通信進(jìn)行了大致的講解,有興趣的可以了解一下
    2017-04-04
  • MyBatis直接執(zhí)行SQL的工具SqlMapper

    MyBatis直接執(zhí)行SQL的工具SqlMapper

    今天小編就為大家分享一篇關(guān)于MyBatis直接執(zhí)行SQL的工具SqlMapper,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java去除中文括號小括號,或者英文括號的實例代碼

    java去除中文括號小括號,或者英文括號的實例代碼

    這篇文章主要介紹了java去除中文括號小括號,或者英文括號的實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • spring aop之鏈?zhǔn)秸{(diào)用的實現(xiàn)

    spring aop之鏈?zhǔn)秸{(diào)用的實現(xiàn)

    這篇文章主要介紹了spring aop之鏈?zhǔn)秸{(diào)用的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • Spring注解驅(qū)動之關(guān)于@Bean注解指定初始化和銷毀的方法

    Spring注解驅(qū)動之關(guān)于@Bean注解指定初始化和銷毀的方法

    這篇文章主要介紹了Spring注解驅(qū)動之關(guān)于@Bean注解指定初始化和銷毀的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評論