Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:
这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportException。Object中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实。
Object提供了一个对象拷贝的默认方法clone方法,但是该方法是有缺陷的,它提供了一种浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:
1、基本类型
如果变量是基本类型,则拷贝其值,比如:int、float、long等。
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; } }