Java中浅拷贝与深拷贝

Java的深浅拷贝 或者 复制

1.基本类型之间的拷贝如:

			int apples = 5;
			int pears = apples;

不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double,long)同样适用于该类情况,其实就是赋值。但是如果你复制的是一个对象,情况就有些复杂了。

2.异常现象:
创建一个类:

		@Data
		public class GoodStudent{
		    private String classNum;
		}

创建一个测试类:

 @Test
    public void test01() {
        GoodStudent goodStudent1 = new GoodStudent();
        GoodStudent goodStudent2 = goodStudent1;
        /**
         * 输出结果:
         * GoodStudent(classNum=11)
         * GoodStudent(classNum=11)
         * 原因是:
         *          上面是将new GoodStudent()对象的引用给了goodStudent2,
         *          然后改了goodStudent2,goodStudent1也就跟着一起变
         */
        goodStudent2.setClassNum("11");
        System.out.println(goodStudent1);
        System.out.println(goodStudent2);
    }

测试结果:

		GoodStudent(classNum=11)
        GoodStudent(classNum=11)

为什么改动了goodStudent2 ,而goodStudent1也跟着一起改动呢,原来是

		GoodStudent goodStudent2 = goodStudent1;

只是将goodStudent1引用的对象赋给了goodStudent2,复制的只是对象引用,所有改动goodStudent2,本会就是改动了引用的对象,所以goodStudent1也会改变!
goodStudent1和goodStudent2 指向内存堆中同一个对象
那么如果不想让goodStudent1 也改变应该怎样做呢?这就要了解对象的拷贝了:

3.浅拷贝:
那么,怎样才能达到复制一个对象呢?
是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;
因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。
要想对一个对象进行复制,就需要对clone方法覆盖。
步骤:
1.新建一个实体类,里面重写了clone() 方法,必须要实现Cloneable接口

@Data
public class GoodStudent implements Cloneable {
    private String classNum;

    public Object clone() {
        GoodStudent stu = null;
        try{
            stu = (GoodStudent)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}

2.新建测试类:

 	@Test
    public void test02() throws CloneNotSupportedException {

        GoodStudent stu1 = new GoodStudent();
        stu1.setClassNum("1");
        /**
         * 这是浅拷贝 调用的是GoodStudent里面对clone方法的重写
         */
        GoodStudent stu2 = (GoodStudent)stu1.clone();
        System.out.println("好学生1:" + stu1.getClassNum());
        System.out.println("好学生2:" + stu2.getClassNum());
        stu2.setClassNum("2");
        System.out.println("好学生1:" + stu1.getClassNum());
        System.out.println("好学生2:" + stu2.getClassNum());
    }

输出结果如下:

好学生1:1
好学生2:1
好学生1:1
好学生2:2

这样就实现了 对 对象的浅拷贝。问题又来了,如果GoodStudent中又有一个对象引用 比如 private Address address,如下代码所示,如果继续使用上面的复制方法,使类实现Cloneable接口,重写protected修饰的clone() 方法,但是里面的Address对象没有实现Cloneable接口,复制的时候,也只是复制的是对象的引用,难道让Address也要实现Cloneable接口吗,如果里面有十个八个对象呢,难道每个都需要吗,如果引用的是第三方的对象又该如何呢?

扫描二维码关注公众号,回复: 6143846 查看本文章
@Data
public class GoodStudent implements Cloneable {

	private Address address;
	
    private String classNum;

    public Object clone() {
        GoodStudent stu = null;
        try{
            stu = (GoodStudent)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}

如果进行上面的操作就是浅拷贝,那如何进行深拷贝呢?

4.深拷贝:
新建一个类:

@Data
public class Dog implements Serializable {
    private String dogName;
}

再建一个类并引用Dog对象:

@Data
public class Animal implements Serializable {
    private String name;
    private Dog dog;
}

这两个类都实现Serializable接口:(必须要实现)

再建一个实现深拷贝的接口实现类:

public class ObjCloner {
    @SuppressWarnings("unchecked")
    public static  <T>T cloneObj(T obj){
        T retVal = null;
        try{
            // 将对象写入流中
            ByteArrayOutputStream ins = new ByteArrayOutputStream();
            ObjectOutputStream inos = new ObjectOutputStream(ins);
            inos.writeObject(obj);
            // 从流中读出对象
            ByteArrayInputStream outs = new ByteArrayInputStream(ins.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(outs);
            retVal = (T)ois.readObject();
        }catch(Exception e){
            e.printStackTrace();
        }
        return retVal;
    }
    
}

测试类:

	@Test
    public void test03(){
        Animal animal = new Animal();
        animal.setName("大象");
        Dog dog = new Dog();
        dog.setDogName("小狗");
        animal.setDog(dog);
        Animal animal1 = ObjCloner.cloneObj(animal);
        System.out.println("动物的名称:"+animal.getName()+"  狗的名称:" 
        						+ animal.getDog().getDogName());
        System.out.println("克隆后动物名称:"+animal1.getName()+"  克隆后狗的名称:" 
        						+ animal1.getDog().getDogName());
        System.out.println(" ----------------------------------------------------------");
        animal1.setName("狮子");
        animal1.getDog().setDogName("小狗狗");
        System.out.println("动物的名称:"+animal.getName()+"  狗的名称:" 
        						+ animal.getDog().getDogName());
        System.out.println("克隆后动物名称:"+animal1.getName()+"  克隆后狗的名称:" 
        						+ animal1.getDog().getDogName());
    }

打印结果如下:

动物的名称:大象  狗的名称:小狗
克隆后动物名称:大象  克隆后狗的名称:小狗
 ---------------------------------------------------------------------------------------
动物的名称:大象  狗的名称:小狗
克隆后动物名称:狮子  克隆后狗的名称:小狗狗

这就实现了,Java对象的复制,也就是深浅拷贝

猜你喜欢

转载自blog.csdn.net/weishuai528/article/details/89714118