一、前言
拷贝的目的就是为了获得相同的对象,当需要属性值相同的对象时,不需要再重新一步一步创建
在Java中的拷贝需要实现Clonable接口,重写Object的clone()方法;同时在Java中的拷贝也分为浅拷贝和深拷贝,其两者的区别就在于对 对象中引用数据类型的不同处理方法。即:
二、浅拷贝
(一)概念
(二)代码说明
 public class Person implements Cloneable{
    private String name;
    private Integer age;
    public String getName(){
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
}
     public static void test01() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(18);
        Person p2=p1.clone();
        System.out.println(p1+":"+p1.hashCode());
        System.out.println(p2+":"+p2.hashCode());
    }
运行结果:
Person{name='小王', age=18}:1324119927
Person{name='小王', age=18}:1915910607
 
 
通过上述代码 我们可以看出拷贝出的Person对象的存储哈希表上的哈希值不一样,说明两个对象的内存位置不同,即成功实现了对象的拷贝。下面的例子将进一步说明成员中引用类型哈希值的变化
Children类:实现Clonable接口
public class Children implements Cloneable{
    private String name;
    private Integer age;
    public String getName(){
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Children{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
} 
 
Person类 其中存在Children类型的成员变量--->即引用类型变量
public class Person implements Cloneable{
    private String name;
    private Integer age;
    private Children child;
    public String getName(){
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setChild(Children child) {
        this.child = child;
    }
    public Children getChild() {
        return child;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public Person clone() throws CloneNotSupportedException {
//        return (Person) super.clone();
        Person clone=(Person)super.clone();//克隆Person对象
        return clone;
    }
}
//以下为测试类
 public static void test02() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(28);
        Children children1=new Children();
        children1.setName("张伟");
        children1.setAge(5);
        p1.setChild(children1);
        Person p2=p1.clone();
        System.out.println(p1+":对象的哈希值"+p1.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
        System.out.println(p2+":对象的哈希值"+p2.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
    } 
 
测试结果:
Person{name='小王', age=28}:对象的哈希值990368553:成员变量的哈希值1096979270
Person{name='小王', age=28}:对象的哈希值2093176254:成员变量的哈希值1096979270 
 
说明 浅拷贝的对象占用不同的内存位置,但引用类型的成员 哈希值一样 ,则说明两对象之间的变量会相互影响。任一个变量的变化会影响到另一个变量。
通过上述的实例,我们归纳以下步骤:
三、深拷贝
(一)概念
(二)代码说明
对Children类重写clone()方法:
  @Override
    protected Children clone() throws CloneNotSupportedException {
        return (Children) super.clone(); 
 
对Person重写clone()方法:
   @Override
    public Person clone() throws CloneNotSupportedException {
//        return (Person) super.clone();
        Person clone=(Person)super.clone();//克隆Person对象
        clone.setChild(child.clone()); //克隆Person中的成员变量 通过成员变量child的副本传参
        return clone;
    } 
 
测试类:
 public static void test04() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(28);
        Children children1=new Children();
        children1.setName("张伟");
        children1.setAge(5);
        p1.setChild(children1);
        Person p2=p1.clone(); //克隆person对象 同时也对Children成员变量进行了克隆 即两者完全剥离
        System.out.println(p1.getChild());
        System.out.println(p2.getChild());
        children1.setName("张三");//单独设置children1的属性
        System.out.println(p1.getChild());
        System.out.println(p2.getChild());
        Children children2=p2.getChild();//此时p2为p1的副本 ,用p2调用getChild方法来获取children对象
        children2.setName("张无忌"); //单独设置children2的属性
        System.out.println(p1.getChild());
        System.out.println(p2.getChild());
        //打印出两个子对象的哈希值 两者哈希值不一样说明 两个对象的存储位置不一样
        System.out.println(p1.getChild().hashCode());
        System.out.println(p2.getChild().hashCode());
    } 
 
Children{name='张伟', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张无忌', age=5}
668386784
1329552164
 
 
从上述代码可以分析出,对对象进行深拷贝后,改变对象中引用类型数据的值 不会影响到另一个对象,通过最后两行的哈希值也可以比较出 两个子对象的哈希值是不相同的,这样就实现了对象间关系的完全脱离,以免对其他对象的内容造成影响。
深拷贝步骤:










