赋值、浅拷贝和深拷贝

时间:2021-10-03 21:40:22

直接赋值

  先定义了一个变量a,然后将a变量赋值给b。则a、b两个变量都指向内存中同一个对象。

public static <T> T[] extendsArray(T[] data){

    int newLength = (data.length * 3)/2 + 1;

    return Arrays.copyOf(data, newLength);
}

public static void main(String[] args) {

    TestClass[] arr = new TestClass[10];
    arr[0] = new TestClass("yanjun", 24);
    TestClass[] arr2 = extendsArray(arr);
    arr2[0].setAge(18);

    System.out.println("arr[0].age: " + arr[0].getAge());//输出18
    System.out.println("arr2[0].age: " + arr2[0].getAge());//输出18
}

浅拷贝

  如果先定义一个a变量,然后使用clone方法拷贝一份给b变量。这实际上是创建一个新的对象给b变量,然后将a变量指向的对象的属性赋值给b变量指向的对象。这是浅拷贝,它对于基本数据类型和String的属性是实现了拷贝,但是对于引用类型的属性(如本例中的cat),两个对象是指向同一个对象。

public static void main(String[] args) {

    TestClass aaa = new TestClass("yanjun", 23);
    aaa.getCat().setColor("red");
    aaa.getCat().setSize(23);

    TestClass bbb = (TestClass) aaa.clone();

    aaa.setName("new yanjun");
    aaa.setAge(18);
    aaa.getCat().setColor("blue");
    aaa.getCat().setSize(18);

    System.out.println(aaa.getName() + "--------" + bbb.getName()); //输出new yanjun--------yanjun
    System.out.println(aaa.getAge() + "--------" + bbb.getAge());//输出18--------23
    System.out.println(aaa.getCat().getColor() + "--------" + bbb.getCat().getColor());//输出blue--------blue
    System.out.println(aaa.getCat().getSize() + "--------" + bbb.getCat().getSize());//输出18--------18

}

class TestClass implements Cloneable{

    private String name;
    private int age;
    private Cat cat;

    public TestClass(String name, int age){
        this.name = name;
        this.age = age;
        this.cat = new Cat();
    }
    //省去get和set方法
    public Object clone(){ 
        Object o=null; 
        try{ 
            o=(TestClass)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。 
        } 
        catch(CloneNotSupportedException e){ 
            System.out.println(e.toString()); 
        } 
        return o; 
    }  
}

class Cat{
    private String color;
    private int size;
    //省去get和set方法
    public Cat() {
        this.color = "red";
        this.size = 23;
    }
}

深拷贝

  深拷贝有两种方式实现:层层clone的方法和利用串行化来做深拷贝

1、层层clone的方法

  在浅拷贝的基础上实现,给引用类型的属性添加克隆方法,并且在拷贝的时候也实现引用类型的拷贝。此种方法由于要在多个地方实现拷贝方法,可能会造成混论。

public static void main(String[] args) {

    TestClass aaa = new TestClass("yanjun", 23);
    aaa.getCat().setColor("red");
    aaa.getCat().setSize(23);

    TestClass bbb = (TestClass) aaa.clone();

    aaa.setName("new yanjun");
    aaa.setAge(18);
    aaa.getCat().setColor("blue");
    aaa.getCat().setSize(18);

    System.out.println(aaa.getName() + "--------" + bbb.getName()); //输出new yanjun--------yanjun
    System.out.println(aaa.getAge() + "--------" + bbb.getAge());//输出18--------23
    System.out.println(aaa.getCat().getColor() + "--------" + bbb.getCat().getColor());//输出blue--------red
    System.out.println(aaa.getCat().getSize() + "--------" + bbb.getCat().getSize());//输出18--------23

}

class TestClass implements Cloneable{

    private String name;
    private int age;
    private Cat cat;

    public TestClass(String name, int age){
        this.name = name;
        this.age = age;
        this.cat = new Cat();
    }
    //省去get和set方法
    public Object clone(){ 
        TestClass o=null; 
        try{ 
            o=(TestClass)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。 
        } 
        catch(CloneNotSupportedException e){ 
            System.out.println(e.toString()); 
        } 
        o.cat = (Cat)o.cat.clone();
        return o; 
    }  
}

class Cat{
    private String color;
    private int size;
    //省去get和set方法
    public Cat() {
        this.color = "red";
        this.size = 23;
    }
    public Object clone(){ 
        Object o=null; 
        try{ 
            o=(Cat)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。 
        } 
        catch(CloneNotSupportedException e){ 
            System.out.println(e.toString()); 
        } 
        return o; 
    }  
}
2、利用串行化来做深拷贝

  为避免复杂对象中使用clone方法可能带来的换乱,可以使用串化来实现深拷贝。先将对象写到流里,然后再重流里读出来。

public Object deepClone() throws IOException, ClassNotFoundException
{ 
    //将对象写到流里 
    ByteArrayOutputStream bo=new ByteArrayOutputStream(); 
    ObjectOutputStream oo=new ObjectOutputStream(bo); 
    oo.writeObject(this); 
    //从流里读出来 
    ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
    ObjectInputStream oi=new ObjectInputStream(bi); 
    return(oi.readObject()); 
}