java 中数组拷贝详细介绍(arraycopy,addAll,序列化和反序列化)

本贴最后更新于 4112 天前,其中的信息可能已经时移世易

一、场景

           有时候由于需要可能需要拷贝数组的中的数据,从而是我们能更好的操作数据

二、使用方法

          在这个时候我们一般会想到数组的拷贝的方式,当然这种方式可以使用,一般有addALL,和System.arraycopy。但一定要注意你的数组中放的是什么数据,是对象还是基本类型的数据。这一点很重要,接下来将通过测试代码详细介绍这些方法。

         1、addAll()和System.arraycopy的区别:

           以下是java底层对addAll实现的方法。可以看到实际上是调用了System.arraycopy

public boolean addAll(int index, Collection<? extends E> c) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: " + index + ", Size: " + size);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew);  // Increments modCount

int numMoved = size - index;
if (numMoved &gt; 0)
    System.arraycopy(elementData, index, elementData, index + numNew,
		     numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}</pre> 

      2、测试放入基本数据类型,和对象之间的区别

     

public class TestArrayCopy {
public static void main(String[] args) {   
    Student[] s = {new Student(18,&quot;Lucy&quot;),new Student(20,&quot;Lily&quot;)};   
    Student[] sBak = new Student[2];   
 
  //arraycopy(Object src, int srcStartIndex, Object dest, int destStartIndex, int length) 
  //从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。 
  //srcStartIndex:原数组中要开始复制的第一个元素的位置 
  //destStartIndex: 目标数组中要开始替换的第一个元素的位置 
  //length: 要复制的元素的个数
    System.out.println(&quot;没修改前&quot;);   
    for(int i=0; i&lt;s.length; i++) {   
        System.out.println(sBak[i] + &quot;\t&quot;);   
    }   
    System.arraycopy(s,0,sBak,0,s.length);
    System.out.println(&quot;------------------拷贝后----&quot;);
    for(int i=0; i&lt;s.length; i++) {   
        System.out.println(sBak[i] + &quot;\t&quot;);   
    }   
    System.out.println();   
    System.out.println(&quot;------------------------------------&quot;);   
    System.out.println(&quot;修改后输出原数组&quot;);   
    s[0].setAge(8888);   
    s[0].setName(&quot;MicXP.com&quot;); //这里改的是sBak[0]引用的对像的值。  
    //sBak[0]=new Student(88,&quot;MicXP&quot;); //这里是直接改sBak[0]引用地址。  
    for(int i=0; i&lt;s.length; i++) {   
    System.out.println(s[i] + &quot;\t&quot;);   
    }   

    System.out.println();   
    System.out.println(&quot;------------------------------------&quot;);   
    System.out.println(&quot;修改后输出拷贝的数组&quot;);    
    for(int i=0; i&lt;s.length; i++) {   
    System.out.println(sBak[i] + &quot;\t&quot;);   
    }   
}   

}
class Student {
private int age ;
private String name ;
Student(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "姓名:"+ this.name +"\t"+"年龄:"+this.age;
}
}

  从以上输出结果可以看出,当我们修改了源数组中的对象,会影响目标数组的对象数据。所以这种拷贝方式是不靠谱的,并没有真正将数据进行复制。

下面是测试基本数据类型的代码。

public class TestArr {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[] = {1,2,3,4};
		int b[] = {2,3,4,5};
		  System.arraycopy(a,0,b,0,a.length);
		  System.out.println("---------拷贝后-----" );
		  System.out.println("a---------->");
		  for(int i=0;i<a.length;i++){
			  System.out.print(a[i]+",");
		  }
		  System.out.println();
		  System.out.println("b---------->");
		  for(int i=0;i<b.length;i++){
			  System.out.print(b[i]+",");
		  }
		  a[3] = 45;
		  System.out.println();
		  System.out.println("--------修改原数组");
		  System.out.println("a---------->");
		  for(int i=0;i<a.length;i++){
			  System.out.print(a[i]+",");
		  }
		  System.out.println();
		  System.out.println("b---------->");
		  for(int i=0;i<b.length;i++){
			  System.out.print(b[i]+",");
		  }
	}

}

从以上数据结果可以看出,当我们拷贝数据后,修改源数组数据,不影响目标数组数据。

所以再数组拷贝的时候要注意这些问题,如果是对象则是拷贝引用。如果是基本数据类型,则拷贝的是真正的数据。

三、疑问

        有什么比较高效的真正拷贝数据的方法?clone?for循环再重新构造?如果你知道你通过评论告诉我,谢谢。

四、疑问的答案

      1、序列化和反序列化

         序列化和反序列化的定义:把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。

      2、序列化和反序列化的应用场景

        永久性保存对象,保存对象的字节序列到本地文件中

        通过序列化在网络中传递对象

        通过序列化在进程间传递对象

       3、可以通过对象的序列化和反序列化来进行对象的深度拷贝

      (数组中的对象需要implements Serializable)

public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {  
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
        ObjectOutputStream out = new ObjectOutputStream(byteOut);  
        out.writeObject(src);
    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
    ObjectInputStream in = new ObjectInputStream(byteIn);  
    @SuppressWarnings(&quot;unchecked&quot;)  
    List&lt;T&gt; dest = (List&lt;T&gt;) in.readObject();  
    return dest;  
}  </pre>
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 数据结构
    88 引用 • 115 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...