java List深拷贝的两种方式

大家都知道java里面分为浅拷贝和深拷贝。举个简单的例子,区分一下浅拷贝和深拷贝的区别

 

public class Address{

    private String address;

    public Address(String address){
        this.address = address;
    }

    public String getAddress(){
        return address;
    }

    public void setAddress(String address){
        this.address = address;
    }

    @Override
    protected Object clone() {
        Address address = null;
        try {
            address = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return address;
    }
}

 

 

 

 

 

 

public class Student implements Cloneable{

	private String name;
	public List
addressList; public Student(){ } public Student(String name) { this.name = name; } public void setName(String name){ this.name = name; } public String getName() { return name; } @Override protected Object clone() { Student student = null; try { student = (Student) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return student; } }

先创建两个类,一个是地址,一个是学生,便于后边的打印结果能明显区分浅拷贝和深拷贝。

 

 

public class myClass {

	public static void main(String[] args) {
		Student student = new Student("李晓东");
		Student student2 = (Student) student.clone();

		println(student.getName() );
		println(student2.getName() );
		println("改变student2的姓名后--------------");
		student2.setName("张天");
		println(student.getName() );
		println(student2.getName());
	}

	public static void println(String str) {
		System.out.println(str);
	}


}

打印结果如下

 

 

李晓东
李晓东
改变student2的姓名后--------------
李晓东
张天

可以看到当我们改变student2的name值的时候,并没有改变student的name值(String在此时不属于引用值类型)
在我们的项目当中,经常会遇到一个类里面有List,然后List装载另外一个对象,这个时候要进行深拷贝就需要用到如下的办法,先把Address进行序列化和实现cloneable接口并且重写clone方法。

 

 

public class Address implements Cloneable,Serializable{

    private String address;

    public Address(String address){
        this.address = address;
    }

    public String getAddress(){
        return address;
    }

    public void setAddress(String address){
        this.address = address;
    }

    @Override
    protected Object clone() {
        Address address = null;
        try {
            address = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return address;
    }
}
public class myClass {

	public static void main(String[] args) {
		List
addressList = new ArrayList<>(); addressList.add(new Address("北京市")); Student student = new Student("李晓东"); student.addressList = addressList; Student student2 = (Student) student.clone(); student2.addressList = depCopy2(addressList); println(student.getName() + "---" + student.addressList.get(0).getAddress()); println(student2.getName() + "---" + student2.addressList.get(0).getAddress()); println("改变student2的姓名后--------------"); student2.setName("张天"); student2.addressList.get(0).setAddress("湖南省"); println(student.getName() + "---" + student.addressList.get(0).getAddress()); println(student2.getName() + "---" + student2.addressList.get(0).getAddress()); } public static void println(String str) { System.out.println(str); } /*** * 方法二 * 需要Address实现cloneable接口和重写clone方法,次方法有限制性, * 例如要先声明List是保存的什么对象,并且当碰到对象里面还持有List集合的时候 * 就不管用的,所以建议使用第一种方法 * * @param addresses * @return */ public static List
depCopy2(List
addresses) { List
destList = new ArrayList<>(); for (Address address : addresses) { destList.add((Address) address.clone()); } return destList; } /*** * 方法一对集合进行深拷贝 注意需要对泛型类进行序列化(实现Serializable) * * @param srcList * @param * @return */ public static List depCopy(List srcList) { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); try { ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(srcList); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream inStream = new ObjectInputStream(byteIn); List destList = (List) inStream.readObject(); return destList; } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } }

此时打印结果是

 

 

李晓东---北京市
李晓东---北京市
改变student2的姓名后--------------
李晓东---北京市
张天---湖南省


如果没看明白,可以自己修改不实现cloneable接口和注释掉clone方法再执行看结果,一定要自己写自己试,这样才会印象深刻!!!

 

 

 

 

 

 

 

你可能感兴趣的:(java基础,android设计模式以及应用)