由于开发过程中只是对目标数据的查询使用,未对源数据进行查看。所以未曾发现操作目标数据会对源数据有影响这个问题。今天总结下深拷贝与浅拷贝的区别。
浅拷贝:若是基本类型,则进行值拷贝;若是引用类型,则进行地址拷贝。但是String类型特殊,它是不可变数据,每次数据修改,会自动创建新对象,分配新地址。
所以基本类型和String类型进行浅拷贝,后对目标数据进行修改,此时目标数据和源数据不一样。而如果是其他引用类型,则会导致目标数据和源数据内容一样。
浅拷贝的常用实现方式
循环遍历对象复制
java
List<Student> destList1=new ArrayList<Student>(srcList.size());
for(Student student : srcList){
destList1.add(student);
}
list构造函数复制
java
List<Student> destList1=new ArrayList<Student>(srcList);
list.addAll()方法复制
java
destList.addAll(srcList);
常见数据类型的浅拷贝
基本数据类型 Integer
java
List<Integer> list1= Arrays.asList(1,2,3);
List<Integer> list2=new ArrayList<>();
list2.addAll(list1);
System.out.println("修改后...");
list2.add(4);
System.out.println(list1); //[1, 2, 3]
System.out.println(list2); //[1, 2, 3, 4]
String类型
java
List<String> list3= Arrays.asList("1","2","3");
List<String> list4=new ArrayList<>();
list4.addAll(list3);
System.out.println("修改后...");
list4.add("4");
System.out.println(list3); //[1, 2, 3]
System.out.println(list4); //[1, 2, 3, 4]
引用类型 对象
java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestCopy {
public static void main(String[] args) {
Student s1=new Student("张三","男");
Student s2=new Student("李四","男");
Student s3=new Student("王五","男");
List<Student> srcList=new ArrayList<>();
srcList.add(s1);
srcList.add(s2);
srcList.add(s3);
List<Student> destList=new ArrayList<>();
destList.addAll(srcList);
System.out.println("修改后...");
for(Student item:destList){
if(item.getName().equals("张三")){
item.setSex("女");
}
}
System.out.println(srcList); //[Student{name='张三', sex='女'}, Student{name='李四', sex='男'}, Student{name='王五', sex='男'}]
System.out.println(destList); //[Student{name='张三', sex='女'}, Student{name='李四', sex='男'}, Student{name='王五', sex='男'}]
}
}
class Student{
String name;
String sex;
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
深拷贝:存储的是内存地址,深拷贝会重新分配地址。目标数据与源数据不会一致。
深拷贝工具类 CloneUtils
java
package com.example.demo.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: lr
* @Description: 深拷贝工具类
*/
public class CloneUtils {
//深拷贝对象
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopy(T object) throws IOException, ClassNotFoundException {
if (object == null) {
return null;
}
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try{
//序列化
oos=new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
//反序列化
ByteArrayInputStream bin=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bin);
return (T) ois.readObject();
}finally {
if(oos!=null){
oos.close();
}
if(ois!=null){
ois.close();
}
}
}
//深拷贝list<对象>集合
@SuppressWarnings("unchecked")
public static <T extends Serializable> List<T> deepCopyList(List<T> srcObj) {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
for (T obj : srcObj) {
oos.writeObject(obj);
}
oos.flush();
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
List<T> deepCopiedList = new ArrayList<T>();
for (int i = 0; i < srcObj.size(); i++) {
deepCopiedList.add((T) ois.readObject());
}
return deepCopiedList;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
} finally {
try {
if (bos != null) bos.close();
if (oos != null) oos.close();
if (bis != null) bis.close();
if (ois != null) ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
测试方法
java
import com.example.demo.util.CloneUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Auther: lr
* @Description:
*/
public class TestCopy {
public static void main(String[] args) {
Student s1=new Student("张三","男");
Student s2=new Student("李四","男");
Student s3=new Student("王五","男");
List<Student> srcList=new ArrayList<>();
srcList.add(s1);
srcList.add(s2);
srcList.add(s3);
//深拷贝
List<Student> destList = CloneUtils.deepCopyList(srcList);
System.out.println("修改后...");
for(Student item:destList){
if(item.getName().equals("张三")){
item.setSex("女");
}
}
System.out.println(srcList); //[Student{name='张三', sex='男'}, Student{name='李四', sex='男'}, Student{name='王五', sex='男'}]
System.out.println(destList); //[Student{name='张三', sex='女'}, Student{name='李四', sex='男'}, Student{name='王五', sex='男'}]
}
}
class Student implements Serializable {
String name;
String sex;
public Student(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
若有错误,还请纠正!