Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:

这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportExceptionObject中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实。

Object提供了一个对象拷贝的默认方法clone方法,但是该方法是有缺陷的,它提供了一种浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:

1、基本类型

如果变量是基本类型,则拷贝其值,比如:intfloatlong等。

2、String字符串

这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。

3、对象

如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。这在Java中很疯狂,因为它突破了访问权限的定义,一个private修饰的变量,竟然可以被两个实例对象访问。

public class Client {
    public static void main(String[] args){
        //定义父亲
        Person p = new Person("父亲");
        //定义大儿子
        Person son1 = new Person("大儿子",p);
        //定义小儿子
        Person son2 = son1.clone();
        //重新给son2起名
        son2.setName("小儿子");
          
        //给小儿子,找个干爹
        son2.getFather().setName("干爹");
          
        System.out.println(son1.getName()+" 的父亲是 "+son1.getFather().getName());
        System.out.println(son2.getName()+" 的父亲是 "+son2.getFather().getName());
    }
}
class Person implements Cloneable{
      
    private String name;
      
    private Person father;
      
    public Person(String name){
        this.name=name;
    }
      
    public Person(String name,Person father){
        this.name=name;
        this.father=father;
    }
      
    //拷贝的实现
    @Override
    public Person clone(){
        Person p = null;
        try{
            //调用Object的浅拷贝
            p = (Person) super.clone();
              
            /**
             * 1.重新覆写对象实例部分的拷贝,实现深拷贝
             * 2.如果没有重写对象实例部分的拷贝,那么大儿子和小儿子的父亲会引用同一个父亲,
             * 只要任意修改一下父亲,另外一个就会被修改
             */
            p.setFather(new Person(p.getFather().getName()));
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return p;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person getFather() {
        return father;
    }
    public void setFather(Person father) {
        this.father = father;
    }
}