Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”.
想用clone方法时报错了,查看一下:
- clone方法被protected修饰.不同包只能在子类中访问,可以用super关键字访问
- clone方法返回类型是Object,所以需要向下转型
- CloneNotSupportedException是受查异常,所以调用它的方法不处理就要throws,main方法不处理就交给JVM处理了
改良的代码
class Person {public String name;public Person(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person("张三");Person person2 = (Person)person1.clone();System.out.println(person2.name);}
}
但还是会报错
要想合法调用 clone 方法, 必须先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常,而它是空的,没有需要重写的方法
如果一个类实现了这个空接口/标记接口,那么证明当前类是可以被克隆的
class Person implements Cloneable{public String name;public Person(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person("张三");Person person2 = (Person)person1.clone();System.out.println(person2.name);}
}
可以用try-catch进行处理,这样就不必用throws将异常报告给抛出异常方法的调用者
class Person implements Cloneable {public String name;public Person(String name) {this.name = name;}@Overridepublic Person clone() {Person person = null;try {person = (Person) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return person;}
}
public class Test {public static void main(String[] args) {Person person = new Person("张三");Person person2 = person.clone();System.out.println(person2.name);}
}
浅拷贝和深拷贝
Cloneable 拷贝出的对象是一份 “浅拷贝”
class Money {public double money = 13;
}
class Person implements Cloneable{public String name;public Money m;public Person(String name) {this.name = name;m = new Money();}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person("张三");Person person2 = (Person)person1.clone();System.out.println("修改之前:"+person1.m.money);System.out.println("修改之前:"+person2.m.money);person2.m.money = 99;System.out.println("修改之后:"+person1.m.money);System.out.println("修改之后:"+person2.m.money);}
}
我们只修改了person2 的money,但person1的money也被改成了99.
内存分布大致是这样的
假设0x56,0x87指向引用地址的对象
我们可以看到,通过clone,我们只是拷贝了Person对象。但是Person对象中的Money对象并
没有拷贝。通过person2这个引用修改了m的值后,person1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝。
改完后person1和person2还是指向同一个m,因为改变基本数据类型不会创建新的对象.
而深拷贝是克隆出一个完全独立于原来对象的对象(如果类中有基本数据类型那就进行拷贝)
代码如下:
class Money implements Cloneable{public double money = 13;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
class Person implements Cloneable{public String name;public Money m;public Person(String name) {this.name = name;m = new Money();}@Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp = (Person) super.clone();tmp.m = (Money)this.m.clone();return tmp;}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person("张三");Person person2 = (Person)person1.clone();System.out.println("修改之前:"+person1.m.money);System.out.println("修改之前:"+person2.m.money);person2.m.money = 99;System.out.println("修改之后:"+person1.m.money);System.out.println("修改之后:"+person2.m.money);}
}
是不是深拷贝,就看程序猿实现的方式怎么样