java的system.arraycopy()方法

java.lang.System的静态方法arraycopy()可以实现数组的复制,讲课的老师说这个方法效率比较高,如果数组有成千上万个元素,那么用这个方法,比用for语句循环快不少。于是我试了试,发现以下问题。 

如果是复制一个一位数组,那么改变复制后的数组并不影响原数组。但是如果复制一个二维数组,那么改变其中任何一个数组,那么另一个的值也发生了变化。开始不是很明白,后来上网查了查资料,理解了其中奥妙。 

java其实没有二维数组的概念,平常实现的二维数组只是元素是一维数组的一维数组,而数组也是引用类型,继承自Object类。数组是new出来的。这些性质也就导致arraycopy()二维数组时出现的问题。 

如果是一维数组,那么元素都是基础类型(如int,double等),使用arraycopy()方法后,是把原数组的值传给了新数组,属于值传递。而如果是二维数组,数组的第一维装的是一个一维数组的引用,第二维里是元素数值。对二维数组应用arraycopy()方法后,第一维的引用被复制给新数组的第一维,也就是两个数组的第一维都指向相同的“那些数组”。而这时改变其中任何一个数组的元素的值,其实都修改了“那些数组”的元素的值,所以原数组和新数组的元素值都一样了。 

OK,就是这样。 

不明白可以看看这个例子: 

Java代码  收藏代码
  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 

Java代码  收藏代码
  1. 01.public static void arraycopy(Object src,       
  2. 02.                             int srcPos,       
  3. 03.                             Object dest,       
  4. 04.                             int destPos,       
  5. 05.                             int length)       
  6. 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中被访问了。

posted @ 2016-09-13 09:04  dy9776  阅读(4088)  评论(0编辑  收藏  举报