1. 程式人生 > >【java】陣列複製幾種方式比較

【java】陣列複製幾種方式比較

import java.util.Arrays;
/**
 * System.arraycopy方法的使用。
 * 從指定源陣列中複製一個數組,複製從指定的位置開始,到目標陣列的指定位置結束 藉助於一個臨時長度為length的陣列
 */
public class LessionSystemArraycopy {
    public static void main(String[] args) {
        // 此方法為native方法。 也就是所非java語言實現的,靠近作業系統底層的語言寫的,供java程式去呼叫
        // public static native void arraycopy(
        // Object src, int srcPos, Object dest,
        // int destPos, int length);
        // 初始化   
        int[] ids = { 1, 2, 3, 4, 5 };
        System.out.println(Arrays.toString(ids)); // [1, 2, 3, 4, 5]
        // 把從索引0開始的2個數字複製到索引為3的位置上
        System.arraycopy(ids, 0, ids, 3, 2);
        System.out.println(Arrays.toString(ids)); // [1, 2, 3, 1, 2]
        // 測試複製到別的陣列上
        // 將資料的索引1開始的3個數據複製到目標的索引為0的位置上
        int[] ids2 = new int[6];
        System.arraycopy(ids, 1, ids2, 0, 3);
        System.out.println(Arrays.toString(ids2)); // [2, 3, 1, 0, 0, 0]
        // 此功能要求
        // 源的起始位置+長度不能超過末尾
        // 目標起始位置+長度不能超過末尾
        // 且所有的引數不能為負數
        try {
            System.arraycopy(ids, 0, ids2, 0, ids.length + 1);
        } catch (IndexOutOfBoundsException ex) {
            // 發生越界異常,資料不會改變
            //ex.printStackTrace();
            System.out.println("拷貝發生異常:資料越界。");
        }
        System.out.println(Arrays.toString(ids2)); // [2, 3, 1, 0, 0, 0]
        // 如果是型別轉換問題
        Object[] o1 = { 1, 2, 3, 4.5, 6.7 };
        Integer[] o2 = new Integer[5];
        System.out.println(Arrays.toString(o2)); // [null, null, null, null, null]
        try {
            System.arraycopy(o1, 0, o2, 0, o1.length);
        } catch (ArrayStoreException ex) {
            // 發生儲存轉換,部分成功的資料會被複制過去
            System.out.println("拷貝發生異常:資料轉換錯誤,無法儲存。");
        }
        // 從結果看,前面3個可以複製的資料已經被儲存了。剩下的則沒有
        System.out.println(Arrays.toString(o2)); // [1, 2, 3, null, null]
    }
}
JAVA語言的下面幾種陣列複製方法中,哪個效率最高?
for迴圈逐一複製
System.arraycopy
Arrays.copyof
使用clone方法


A、for迴圈的話,很靈活,但是程式碼不夠簡潔. 

B、System.arraycopy()原始碼。可以看到是native方法:native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前檔案,而是在用其他語言(如C和C++)實現的檔案中。
  可以將native方法比作Java程式同C程式的介面。

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

native方法:
Java不是完美的,Java的不足除了體現在執行速度上要比傳統的C++慢許多之外,Java無法直接訪問到作業系統底層(如系統硬體等),為此Java使用native方法來擴充套件Java程式的功能。
可以將native方法比作Java程式同C程式的介面,其實現步驟:
1、在Java中宣告native()方法,然後編譯;
2、用javah產生一個.h檔案;
3、寫一個.cpp檔案實現native匯出方法,其中需要包含第二步產生的.h檔案(注意其中又包含了JDK帶的jni.h檔案);
4、將第三步的.cpp檔案編譯成動態連結庫檔案;
5、在Java中用System.loadLibrary()方法載入第四步產生的動態連結庫檔案,這個native()方法就可以在Java中被訪問了。

C、選項有誤,copyOf不是System的方法,而是Arrays的方法,
下面是原始碼,可以看到本質上是呼叫的arraycopy方法。,那麼其效率必然是比不上arraycopy的
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;}

D。clone的話,返回的是Object【】,需要強制轉換。 一般用clone效率是最差的


參考資料:
http://blog.csdn.net/kesalin/article/details/566354
http://xuyuanshuaaa.iteye.com/blog/1046621
https://www.nowcoder.com/questionTerminal/915a9a1f5a3a4a6bbe5011c090bdf137

package Test;

public class TestLoader {
    public static void main(String[] args) {
        String[] s1 = {"中國","山西","太原","TYUT","zyy","加拿大","不知道哪個州","不知道哪個市","不知道哪個學校","yxf"};
        String[] s2 = new String[10];
        System.arraycopy(s1, 0, s2, 0, 10);
        s2[6] = "假設蒙大拿州";
        s2[7] = "假設蒙特利爾市";
        s2[8] = "假設Montreal商學院";

        System.out.println("This is s1");
        for(int i = 0;i < s1.length ;i++){
            System.out.print(s1[i] + ",");
        }

        System.out.println("\nThis is s2");
        for(int i = 0;i < s2.length ;i++){
            System.out.print(s2[i] + ",");
        }

        String[][] s3 = {{"中國","山西","太原","TYUT","zyy"},{"加拿大","不知道哪個州","不知道哪個市","不知道哪個學校","yxf"}};
        String[][] s4 = new String[s3.length][s3[0].length];
        System.arraycopy(s3, 0, s4, 0, s3.length);

        System.out.println("\nThis is original s3");
        for(int i = 0;i < s3.length ;i++){
            for(int j = 0; j< s3[0].length ;j++){
                System.out.print(s3[i][j] + ",");
            }
        }

        s4[1][1] = "假設蒙大拿州";
        s4[1][2] = "假設蒙特利爾市";
        s4[1][3] = "假設Montreal商學院";

        System.out.println("\nThis is s3 after s4 has changed.");
        for(int i = 0;i < s3.length ;i++){
            for(int j = 0; j< s3[0].length ;j++){
                System.out.print(s3[i][j] + ",");
            }
        }

        System.out.println("\nThis is s4");
        for(int i = 0;i < s4.length ;i++){
            for(int j = 0; j < s4[0].length ; j++){
                System.out.print(s4[i][j] + ",");
            }

        }

    }

}
/*
        * 現象:
        * 如果是複製一個一位陣列,那麼改變複製後的陣列並不影響原陣列。
        * 但是如果複製一個二維陣列,那麼改變其中任何一個數組,那麼另一個的值也發生了變化
        * */

        /*
        * 原因:
        * 如果是一維陣列,那麼元素都是基礎型別(如int,double等),使用arraycopy()方法後,是把原陣列的值傳給了新陣列,屬於值傳遞。
        * 而如果是二維陣列,陣列的第一維裝的是一個一維陣列的引用,第二維裡是元素數值
        * 對二維陣列應用arraycopy()方法後,第一維的引用被複制給新陣列的第一維,也就是兩個陣列的第一維都指向相同的“那些陣列”。
        * 而這時改變其中任何一個數組的元素的值,其實都修改了“那些陣列”的元素的值,所以原陣列和新陣列的元素值都一樣了。
        * */


package Test;

import java.util.Arrays;

public class HelloWorld{
    public static void main(String[] args) {
        int[] src = new int[1024 * 1024 * 100];
        int[] dest = new int[1024 * 1024 * 100];
        for (int i = 0; i < src.length; i++)
        {src[i] = i;}
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < src.length; i++) {
            dest[i] = src[i];
        }
        long endTime = System.currentTimeMillis();
        System.out.println("for : " + (endTime - startTime));
        startTime = System.currentTimeMillis();
        System.arraycopy(src, 0, dest, 0, src.length);
        endTime = System.currentTimeMillis();
        System.out.println("arraycopy : " + (endTime - startTime));
        startTime = System.currentTimeMillis();
        dest = Arrays.copyOf(src, src.length);
        endTime = System.currentTimeMillis();
        System.out.println("copyOf : " + (endTime - startTime));
        startTime = System.currentTimeMillis();
        dest = src.clone();
        endTime = System.currentTimeMillis();
        System.out.println("clone : " + (endTime - startTime));
    }
}
/*
for : 86
arraycopy : 86
copyOf : 174
clone : 278

* for和arraycopy是差不多的
* copyof比clone快
* */