一、标记接口Clonable
声明如下
public interface Clonable{} 可以注意到这个接口内没有定义任何方法。
如果一个类实现(implements )了Clonable接口,意味着这个类内重写了Object的clone方法。
如果类内重写了Object的clone方法却没有实现Clonable接口,编译器会抛出CloneNoSupportedException异常。
在Object类中的clone方法是protected方法,关于这个复杂的权限问题请看:
Java中protected方法访问权限的问题
子类必须重写父类方法,将clone方法设为public 或 protected 方法,子类的实例对象才有可能在其他类中调用重写后的clone方法,
否则不能在其他类中用 子类的实例对象 调用 父类的protected方法(除非大家都在一个包内)。
子类重写时还能修改clone的返回类型。
二、浅拷贝
浅拷贝有两种层次:
①使用 = 号进行拷贝:被拷贝的对象并没有多一份,还是原来那一份,只是多了个新的对象变量去引用它。
class Person{ private String name = "first"; private Student student; public void changeName(String name){ this.name = name; } public String getName(){ return name; }}class Man{ private int id = 7;}public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP; } } 这里的newP 和 oldP 指向内存空间的同一个对象,newP对自己指向的对象进行修改操作等于对oldP指向的对象进行修改。
public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP; newP.changeName("Second"); System.out.println(oldP.getName()); } 最后一条输出语句将会输出Second,说明newP做的操作是在oldP指向的对象上进行的,二者指向同一对象。
②使用object类中的clone方法:进行更深一点的拷贝,但是还不够深。
如第一部分所言,必须实现Clonable接口,但在重写Object类的clone方法时 调用的是父类用protected保护的clone方法,并没有定义新花样。
class Person implements Clonable{ private String name = "first"; private Student student; public void changeName(String name){ this.name = name; } public String getName(){ return name; } @Override public Person clone() throws CloneNoSupportException{ return (Employee)super.clone(); } /**新增两个方法*/ public void setId(int id){ this.student.id = id; } public void getId(){ return this.student.id;}class Man{ private int id = 7;}public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP.clone(); //实现Clonable的目的是为了此时oldP对象可以在Test类中调用clone方法(此时oldP的clone方法内再调用Object类中用protected保护的clone方法) } } oldP和newP引用的对象关系如下图:
接着使用newP进行修改操作:
public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP.clone(); //实现Clonable的目的是为了此时oldP对象可以在Test类中调用clone方法(此时oldP的clone方法内再调用Object类中用protected保护的clone方法) newP.changeName("Second"); System.out.println(oldP.getName()); //输出:First newP.setId(20); System.out.println(oldP.getId()); //输出:20 } } 输出结果表明,实际情况是图中所示的情况。Object类中的clone方法没有拷贝对象中定义的其他类型对象,话不多说,看图就成。
三、深拷贝
直接上图,深拷贝就是要旧的和新的 除了值相等外,其他没有瓜葛。
class Person implements Clonable{ private String name = "first"; private Student student; public void changeName(String name){ this.name = name; } public String getName(){ return name; } @Override public Person clone() throws CloneNoSupportException{ Person newOne = (Person) super.clone(); newOne.student = (Student) student.clone(); return newOne; } /**新增两个方法*/ public void setId(int id){ this.student.id = id; } public void getId(){ return this.student.id;}class Man{ private int id = 7;}public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP.clone(); //实现Clonable的目的是为了此时oldP对象可以在Test类中调用clone方法(此时oldP的clone方法内再调用Object类中用protected保护的clone方法) } } 执行以下修改操作
public class Test{ public static void main(String[] args){ Person oldP = new Person(); Person newP = oldP.clone(); //实现Clonable的目的是为了此时oldP对象可以在Test类中调用clone方法(此时oldP的clone方法内再调用Object类中用protected保护的clone方法) newP.changeName("Second"); System.out.println(oldP.getName()); //输出:First newP.setId(20); System.out.println(oldP.getId()); //输出:7 } } newP 和 oldP 对象各自修改各自的,互不影响。