關於System.arrayCopy()方法
java其實沒有二維陣列的概念,平常實現的二維陣列只是元素是一維陣列的一維陣列,而陣列也是引用型別,繼承自Object類。陣列是new出來的。這些性質也就導致arraycopy()二維陣列時出現的問題。
1、首先對於一維陣列,如果元素都是基礎型別(如int,double等),使用arraycopy()方法後,是把原陣列的值傳給了新陣列,屬於值傳遞,故修改複製後的陣列,原陣列不受到影響。如果是不可變類如String,雖然屬於引用傳遞,但是具有不可變的特徵,故修改複製後的陣列,原陣列不受到影響。 2、對於二維陣列,陣列的第一維裝的是一個一維陣列的引用,第二維裡是元素數值。對二維陣列應用arraycopy()方法後,第一維的引用被複制給新陣列的第一維,也就是兩個陣列的第一維都指向相同的“那些陣列”。而這時改變其中任何一個數組的元素的值,其實都修改了“那些陣列”的元素的值,所以原陣列和新陣列的元素值都一樣了。
System.arraycopy()的實現方法: 首先檢視System.arraycopy()的API public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)將指定源陣列中的陣列從指定位置複製到目標陣列的指定位置。 陣列元件的一個子序列被從通過引用的源陣列複製src被引用的目標陣列dest 。 複製的元件數量等於length引數。 源陣列中位置srcPos至srcPos+length-1的元件分別複製到目標陣列的位置destPos至destPos+length-1 。 如果src個dest引數指代相同的陣列物件,則被處理是否在位置上的部件進行復印srcPos通過srcPos+length-1首先被複制到一個臨時的陣列length組分,然後將臨時陣列的內容被複制到的位置destPos通過destPos+length-1目標陣列的。
其中 Arrays.copy是JDK1.6中引用的新方法。它呼叫了System.arraycopy完成相關陣列的複製。 在JDK1.6中ArrayList的相關add remove等操作都是呼叫System.arraycopy來對其底層的Object[]elementData陣列進行操作的。 LinkedList則使用一個Entry的內部類,其有指向next和previous的引用儲存元素,它的遍歷則先計算出所需index和size>>1(以為後的大小),確定是通過previous還是next遍歷。 檢視System.arraycopy() 的原始碼: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 可以看到它是native方法,一般是藉助C/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中被訪問了。
最後關於幾種陣列複製的效率問題: 1、for迴圈,手動複製 2、System.arraycopy()方法 3、Arrays.copyOf()方法 4、clone()方法 結論: 由於System.arraycopy()是最貼近底層的,其使用的是記憶體複製,省去了大量的陣列定址訪問等時間,故效率最高。 對於Arrays.copyOf()方法檢視原始碼可以看到: 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; } 它是藉助System.arraycopy()方法實現的,故效率次於System.arraycopy() clone()方法效率是最低的,一般需要重寫,clone的方法Object執行特定的克隆操作。 首先,如果此物件的類不實現介面Cloneable ,則丟擲CloneNotSupportedException 。 請注意,所有陣列都被認為是實現介面Cloneable ,並且陣列型別T[]的clone方法的返回型別是T[] ,其中T是任何引用或原始型別。 否則,該方法將建立該物件的類的新例項,並將其所有欄位初始化為完全符合該物件的相應欄位的內容,就像通過賦值一樣。 這些欄位的內容本身不被克隆。 因此,該方法執行該物件的“淺拷貝”,而不是“深度拷貝”操作。如果需要“深度拷貝”操作,則需要遞迴clone() 對於陣列空間小的情況下,前三種差別不大,對於比較大的陣列,便可以明顯看出差別。