当前位置: 首页 > 图灵资讯 > 技术篇> java List复制:浅拷贝与深拷贝

java List复制:浅拷贝与深拷贝

来源:图灵教育
时间:2023-07-02 17:10:31

Java拷贝可分为三种:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)。除了java中的基本数据类型(int,long,short等。),还有引用数据类型,如string和对象实例。对于基本数据类型,实际上是复制其值,而对于引用数据类型,复制是其引用,没有创建新的对象,即没有分配新的内存空间。这种拷贝叫浅拷贝。深拷贝是指在引用类型进行拷贝时,创建新的对象,即将新的内存空间分配给拷贝对象。我们来看看浅拷贝和深拷贝的区别。众所周知,list本质上是一个数组,而数组是以地址的形式存储的。如上图所示list 给list一个浅拷贝 B,由于是浅拷贝,A的内容直接复制给B。java中相同内容的数组指向相同的地址,即在浅拷贝后,a和B指向相同的地址。结果是,在改变B的同时,也会改变A,因为改变B是改变B指向地址的内容,因为A也指向同一地址,所以A和B一起改变。几种浅拷贝1、复制遍历循环1 List<Person> destList = new ArrayList<Person>(srcList.size());  2 for(Person p : srcList){  3     destList.add(p);  4 }  2、Listt实现类的结构方法<Person> destList = new ArrayList<Person>(srcList);  3、使用list.addAll()List方法<Person> destList = new ArrayList<Person>();  destList.addAll(srcList);  4、使用System.arraycopy()方法1 Person[] srcPersons=srcList.toArray(new Person[0]); 2 Person[] destPersons=new Person[srcPersons.length]; 3 System.arraycopy(srcPersons, 0, destPersons, 0, srcPersons.length); 5、使用StreamcopyListt<Person> destList = srcList.stream().collect(Collectors.toList());测试及结果 1 printList(destList); ////打印A之前没有改变B  2 srcList.get(0).setAge(100);//改变B   3 printList(destList); ////打印改变B后的A 4 ///打印结果  5 123-->20   6 ABC-->21   7 abc-->22   8 123-->100   9 ABC-->21  10 abc-->22  如图所示,List深度复制,在将A复制到B的同时,为B创建新的地址,然后将地址A的内容传递到地址B。Lista与ListB内容一致,但由于指向的地址不同,相互变化不受影响。1.使用序列化方法 1   /** 2      * 深度复制集合 3      * 注意需要年泛型的序列化(实现serializable) 4      * 5      * @param src 6      * @param <T> 7      * @return 8      * @throws IOException 9      * @throws clasnotfoundexception      */11     public static <T> List<T> deepCopy(List<T> src) {12         try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();13              ObjectOutputStream outputStream = new ObjectOutputStream(byteOut);14         ) {15             outputStream.writeObject(src);16             try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());17                  ObjectInputStream inputStream = new ObjectInputStream(byteIn);18             ) {19                 return (List<T>) inputStream.readObject();20             }21         } catch (Exception e) {22             ThrowableUtils.getString(e);23         }24         return Collections.emptyList();25     }2.clone方法 1 public class A implements Cloneable {  2     public String name[];  3     public A(){ name=new String[2]; }  4     public Object clone() {  5         A o = null;  6         try {  7             o = (A) super.clone();  8         } catch (CloneNotSupportedException e) {         9             e.printStackTrace(); 10         } return o; 11     } 12 } 13 14 for(int i=0;i<n;i+=){ 15     copy.add((A)src.get(i).clone()); 16 }Java对象的处理不同于基本数据类型。在Java中,以对象为入口参数的传输缺少为“引用传输”,即只传递一个“引用”,与C语言中的指针引用相同。在Java中,以对象为入口参数的传输缺少为“引用传输”,即只传输一个“引用”,这个“引用”的概念与C语言中的指针引用相同。当函数体内输入变量发生变化时,本质上是对对象的直接操作。 除函数传值时为“引用传递”外,在任何使用中”=“向对象变量赋值时,都是“引用传递”。测试及结果 1 printList(destList); ////打印A之前没有改变B  2 srcList.get(0).setAge(100);//改变B   3 printList(destList); ////打印改变B后的A  4  5 123-->20   6 ABC-->21   7 abc-->22   8 123-->20   9 ABC-->21  10 abc-->22  在浅复制的情况下,在源数据被修改和破坏后,指向数据目标集合的相应元素也发生了相同的变化。因此,在需求要求必须深度复制的情况下,如果使用上述方法,请确保List中的T对象不易被外部修改和损坏。因此,在需求要求必须深度复制的情况下,如果使用上述方法,请确保List中的T对象不易被外部修改和损坏。参考: