java.lang.System的靜態方法arraycopy()可以實現數組的復制,講課的老師說這個方法效率比較高,如果數組有成千上萬個元素,那么用這個方法,比用for語句循環快不少。於是我試了試,發現以下問題。
如果是復制一個一位數組,那么改變復制后的數組並不影響原數組。但是如果復制一個二維數組,那么改變其中任何一個數組,那么另一個的值也發生了變化。開始不是很明白,后來上網查了查資料,理解了其中奧妙。
java其實沒有二維數組的概念,平常實現的二維數組只是元素是一維數組的一維數組,而數組也是引用類型,繼承自Object類。數組是new出來的。這些性質也就導致arraycopy()二維數組時出現的問題。
如果是一維數組,那么元素都是基礎類型(如int,double等),使用arraycopy()方法后,是把原數組的值傳給了新數組,屬於值傳遞。而如果是二維數組,數組的第一維裝的是一個一維數組的引用,第二維里是元素數值。對二維數組應用arraycopy()方法后,第一維的引用被復制給新數組的第一維,也就是兩個數組的第一維都指向相同的“那些數組”。而這時改變其中任何一個數組的元素的值,其實都修改了“那些數組”的元素的值,所以原數組和新數組的元素值都一樣了。
OK,就是這樣。
不明白可以看看這個例子:
1 public class TestArrayCopy { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 // TODO 自動生成方法存根 8 9 String[] s1 = {"中國","山西","太原","TYUT","zyy","加拿大","不知道哪個州","不知道哪個市","不知道哪個學校","yxf"}; 10 String[] s2 = new String[10]; 11 System.arraycopy(s1, 0, s2, 0, 10); 12 s2[6] = "假設蒙大拿州"; 13 s2[7] = "假設蒙特利爾市"; 14 s2[8] = "假設Montreal商學院"; 15 16 System.out.println("This is s1"); 17 for(int i = 0;i < s1.length ;i++){ 18 System.out.print(s1[i] + ","); 19 } 20 21 System.out.println("\nThis is s2"); 22 for(int i = 0;i < s2.length ;i++){ 23 System.out.print(s2[i] + ","); 24 } 25 26 String[][] s3 = {{"中國","山西","太原","TYUT","zyy"},{"加拿大","不知道哪個州","不知道哪個市","不知道哪個學校","yxf"}}; 27 String[][] s4 = new String[s3.length][s3[0].length]; 28 System.arraycopy(s3, 0, s4, 0, s3.length); 29 30 System.out.println("\nThis is original s3"); 31 for(int i = 0;i < s3.length ;i++){ 32 for(int j = 0; j< s3[0].length ;j++){ 33 System.out.print(s3[i][j] + ","); 34 } 35 } 36 37 s4[1][1] = "假設蒙大拿州"; 38 s4[1][2] = "假設蒙特利爾市"; 39 s4[1][3] = "假設Montreal商學院"; 40 41 System.out.println("\nThis is s3 after s4 has changed."); 42 for(int i = 0;i < s3.length ;i++){ 43 for(int j = 0; j< s3[0].length ;j++){ 44 System.out.print(s3[i][j] + ","); 45 } 46 } 47 48 System.out.println("\nThis is s4"); 49 for(int i = 0;i < s4.length ;i++){ 50 for(int j = 0; j < s4[0].length ; j++){ 51 System.out.print(s4[i][j] + ","); 52 } 53 54 } 55 } 56 57 }
結果:
This is s1
中國,山西,太原,TYUT,zyy,加拿大,不知道哪個州,不知道哪個市,不知道哪個學校,yxf,
This is s2
中國,山西,太原,TYUT,zyy,加拿大,假設蒙大拿州,假設蒙特利爾市,假設Montreal商學院,yxf,
This is original s3
中國,山西,太原,TYUT,zyy,加拿大,不知道哪個州,不知道哪個市,不知道哪個學校,yxf,
This is s3 after s4 has changed.
中國,山西,太原,TYUT,zyy,加拿大,假設蒙大拿州,假設蒙特利爾市,假設Montreal商學院,yxf,
This is s4
中國,山西,太原,TYUT,zyy,加拿大,假設蒙大拿州,假設蒙特利爾市,假設Montreal商學院,yxf,
arraycopy的實現方法:
其中 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
- 01.public static void arraycopy(Object src,
- 02. int srcPos,
- 03. Object dest,
- 04. int destPos,
- 05. int length)
- 06. 從指定源數組中復制一個數組,復制從指定的位置開始,到目標數組的指定位置結束。從 src 引用的源數組到 dest 引用的目標數組,數組組件的一個子序列被復制下來。被復制的組件的編號等於 length 參數。源數組中位置在 srcPos 到 srcPos+length-1 之間的組件被分別復制到目標數組中的 destPos 到 destPos+length-1 位置。
它是個native方法,測試結果表明,
當數組很小,但存是調用次數多的話。
使用它復制數組並不比for循環手工復制數組快。
但是如果是數組比較大,那么使用System.arraycopy會比較有優勢,因為其使用的是內存復制,省去了大量的數組尋址訪問等時間。
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中被訪問了。