深拷贝和浅拷贝

Object 类的clone() 方法 : 

  clone() 指创建并返回此对象的一个副本。(通过clone()方法返回一个新的对象,且新的对象的属性值从原对象拷贝)。

  clone() 是 Object 类的方法,所以每一个类都会从Object类继承此方法。

如何实现clone :  实现 Cloneable 接口 , 重写clone() 方法

  使用某个类的clone()方法,必须要实现 Cloneable 接口。否则会抛 java.lang.CloneNotSupportedException)因为Object 类本身不实现Cloneable接口,所以使用Object对象调用clone()方法时会抛出运行时异常 java.lang.CloneNotSupportedException。

  Object 类的 clone()方法是 protected修饰的,所以要重写clone()方法,并且将 protected 改为 public修饰。

@Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

 

 从内存分析深拷贝和浅拷贝的区别,以Car和Wheel为例

 

package com.nemo.clone;
// 车轮 类
public class Wheel {
    private String name;

    public Wheel(String name) {
        this.name = name;
    }
    
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
package com.nemo.clone;

public class Car implements Cloneable {
    private int id;
    private String type;
    //汽车 和 车轮 是组合关系
    private Wheel wheel;

    public Car (Wheel wheel) {
        this.wheel = wheel;
    }
    
    // 重写 clone() 方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public Wheel getWheel() {
        return wheel;
    }

    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }
}
package com.nemo.clone;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Wheel wheel = new Wheel("XXX"); // 创建一个车轮
        Car car = new Car(wheel);
        car.setId(123);
        car.setType("Audi");
        car.getWheel().setName("AAA"); //将车轮的name改为 AAA
        
        Car cloneCar = (Car)car.clone(); // clone 一个Car 
        cloneCar.setId(456); 
        cloneCar.setType("Benz");
        
        cloneCar.getWheel().setName("BBB"); // 通过cloneCar 将车轮的name 改为 BBB
        
        System.out.println(car);
        System.out.println(car.getId() + "  " + car.getType());
        System.out.println(car.getWheel());
        System.out.println(car.getWheel().getName());
        System.out.println("------------------------------------------");
        System.out.println(cloneCar);
        System.out.println(cloneCar.getId() + "  " + cloneCar.getType());
        System.out.println(cloneCar.getWheel());
        System.out.println(cloneCar.getWheel().getName());
    }
}
com.nemo.clone.Car@1fb8ee3
123  Audi
com.nemo.clone.Wheel@61de33
BBB
------------------------------------------
com.nemo.clone.Car@14318bb
456  Benz
com.nemo.clone.Wheel@61de33
BBB


从输出可以看出 car和拷贝出来的cloneCar的哈希码不同,car 的 id,type 和 cloneCar的id,type 也不同。(红色标识)
car的Wheel对象和cloneCar的Wheel对象哈希码相同,说明他们共享一个Wheel引用。所以当car更改了Wheel的name为"AAA"后cloneCar也更改Wheel的name为"BBB"最后car和cloneCar的name都输出BBB。(car和cloneCar共享一个引用 cloneCar后执行cloneCar.getWheel.setName("BBB") );

(哈希码 : 指的是JAVA通过某算法将对象的地址生成16进制的字符串。用于唯一标识某对象)

 

以上为浅拷贝。

 

下面是深拷贝的例子

package com.nemo.clone;
// 车轮 类
public class Wheel implements Cloneable{
    private String name;

    public Wheel(String name) {
        this.name = name;
    }
    
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    
    // 重写 clone() 方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
package com.nemo.clone;

public class Car implements Cloneable {
    private int id;
    private String type;
    //汽车 和 车轮 是组合关系
    private Wheel wheel;

    public Car (Wheel wheel) {
        this.wheel = wheel;
    }
    
    // 重写 clone() 方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        Car object =  (Car)super.clone();
        object.wheel = (Wheel)wheel.clone();
        return object;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public Wheel getWheel() {
        return wheel;
    }

    public void setWheel(Wheel wheel) {
        this.wheel = wheel;
    }
}
package com.nemo.clone;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Wheel wheel = new Wheel("XXX"); // 创建一个车轮
        Car car = new Car(wheel);
        car.setId(123);
        car.setType("Audi");
        car.getWheel().setName("AAA"); //将车轮的name改为 AAA
        
        Car cloneCar = (Car)car.clone(); // clone 一个Car 
        cloneCar.setId(456); 
        cloneCar.setType("Benz");
        
        cloneCar.getWheel().setName("BBB"); // 通过cloneCar 将车轮的name 改为 BBB
        
        System.out.println(car);
        System.out.println(car.getId() + "  " + car.getType());
        System.out.println(car.getWheel());
        System.out.println(car.getWheel().getName());
        System.out.println("------------------------------------------");
        System.out.println(cloneCar);
        System.out.println(cloneCar.getId() + "  " + cloneCar.getType());
        System.out.println(cloneCar.getWheel());
        System.out.println(cloneCar.getWheel().getName());
    }
}
输出结果 : 
com.nemo.clone.Car@1fb8ee3
123 Audi com.nemo.clone.Wheel@61de33 AAA ------------------------------------------ com.nemo.clone.Car@14318bb 456 Benz com.nemo.clone.Wheel@ca0b6 BBB

(红色标识的是与上一个例子不同的地方)
从输出结果可以看出 car和cloneCar的Wheel对象哈希码不同,说明car和cloneCar不再共享同一wheel对象。

 

 

 

 (

  采用clone()方法这种方式拷贝对象,其实并不好用。每一个类都需要实现cloneable接口,重写clone方法。当类的等级结构很深的时候会很乱。

  另一种拷贝对象的方法是 采用序列化的方式。

   // JAVA创建对象的几种方式

)

 

 

 

posted @ 2014-04-10 18:09  廖东海  阅读(386)  评论(0编辑  收藏  举报