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

Java數組擴容的三大小結

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

方案1:新建數組

這種方法新建的數組必須要比原先的長度要長,然后將原來的數組內容移到新的數組中

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

輸出結果

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

方案2:Arrays.copyOf

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

輸出結果

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

Arrays.copyof是用于數組進行復制時常使用的方法,本身在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;
}

通過上面的代碼可以看出,其本質是調用了System.arraycopy方法。

先產生一個新的數組然后調用arraycopy方法最后在返回產生的新數組。但是我們進行數組擴容的時候禪城了新數組,但是原數組依然存在,造成了內存的浪費。

方案3:System.arraycopy

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

輸出結果

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

arraycopy源碼

/**
     * @param src     the source array.  源數組
     * @param srcPos  starting position in the source array. 要復制的源數組的起始位置
     * @param dest    the destination array. 目標數組
     * @param destPos starting position in the destination data. 目標數組的起始位置
     * @param length  the number of array elements to be copied. 要復制的長度
     * @throws IndexOutOfBoundsException if copying would cause
     *                                   access of data outside array bounds.
     *                                   如果復制會導致數據的訪問超出數組邊界。
     *                                   則會報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數組中的元素存儲到dest數組中。
     *                                   則會報 ArrayStoreException數組存儲異常
     * @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. 從舊數組拷貝到新數組

//從舊數組拷貝到新數組
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()深層理解

深復制還是淺復制

先說結論 :

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

引用對象

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

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

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

一維數組和多維數組

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

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

線程是否安全(摘自網絡)

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 來保證拷貝線程先已經運行了.
            condition.await();
            lock.unlock();
?
            Thread.sleep(2); // 休眠2毫秒, 確??截惒僮饕呀泩?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 的內容. 為了確保 copy() 操作先于 modify() 操作, 我使用 Condition, 并且延時了兩毫秒, 以此來保證執(zhí)行拷貝操作(即System.arraycopy) 先于修改操作.

根據第三點, 如果 System.arraycopy 是線程安全的, 那么先執(zhí)行拷貝操作, 再執(zhí)行修改操作時, 不會影響復制結果, 因此 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)

結論 :System.ayyaycopy是不安全的。

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

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

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

相關文章

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

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

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

    tomcat請求流程源碼解進階篇

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

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

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

    Spring Boot如何防止重復提交

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

    HttpMessageConverter報文信息轉換器的深入講解

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

    淺析Java中如何實現線程之間通信

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

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

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

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

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

    spring aop之鏈式調用的實現

    這篇文章主要介紹了spring aop之鏈式調用的實現,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • Spring注解驅動之關于@Bean注解指定初始化和銷毀的方法

    Spring注解驅動之關于@Bean注解指定初始化和銷毀的方法

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

最新評論