java.lang.System的靜態方法arraycopy()可以實現數組的復制,講課的老師說這個方法效率比較高,如果數組有成千上萬個元素,那么用這個方法,比用for語句循環快不少。於是我試了試,發現以下問題。
如果是復制一個一位數組,那么改變復制后的數組並不影響原數組。但是如果復制一個二維數組,那么改變其中任何一個數組,那么另一個的值也發生了變化。開始不是很明白,后來上網查了查資料,理解了其中奧妙。
java其實沒有二維數組的概念,平常實現的二維數組只是元素是一維數組的一維數組,而數組也是引用類型,繼承自Object類。數組是new出來的。這些性質也就導致arraycopy()二維數組時出現的問題。
如果是一維數組,那么元素都是基礎類型(如int,double等),使用arraycopy()方法后,是把原數組的值傳給了新數組,屬於值傳遞。而如果是二維數組,數組的第一維裝的是一個一維數組的引用,第二維里是元素數值。對二維數組應用arraycopy()方法后,第一維的引用被復制給新數組的第一維,也就是兩個數組的第一維都指向相同的“那些數組”。而這時改變其中任何一個數組的元素的值,其實都修改了“那些數組”的元素的值,所以原數組和新數組的元素值都一樣了。
OK,就是這樣。
不明白可以看看這個例子:
- public class TestArrayCopy {
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO 自動生成方法存根
- 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] + ",");
- }
- }
- }
- }
結果:
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中被訪問了。