被复制对象的所有基础类型变量(byte,short,int,long,char,boolean,float,double)与原有对象中变量具有相同的值,修改其值不会影响原对象;而复制对象中引用类型(数组,类对象等)还是指向原来对象,修改其值会影响原对象。
被复制对象的所有基础类型变量(byte,short,int,long,char,boolean,float,double)与原有对象中变量具有相同的值,修改其值不会影响原对象;并且复制对象中引用类型(数组,类对象等)指向被复制过的新对象,修改其值不会影响原对象。
java.lang.Object 类包含 clone()方法:
protected native Object clone() throws
CloneNotSupportedException;
// 1.native方法,本地方法,效率高于非native方法。
// 2.访问修饰符protected,Object子类可以使用clone(),同时为了其它类可以调用clone(),必须将Object子类重写的clone()访问修饰符改为public。
// 3.clone()返回Object,需强制类型转换
对任何对象x, x.clone() != x; 不是同一个对象
被克隆的对象都是通过super.clone()方法获取当前对象的副本;当前对象必须实现了Cloneable接口,否则会抛出CloneNotSupportedException。
class Employer {
private String employerName;
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmployerName() {
return employerName;
}
public void setEmployerName(String employerName) {
this.employerName = employerName;
}
public Employer(String employerName, int age){
this.employerName = employerName;
this.age = age;
}
}
class Employee implements Cloneable{
private String employeeName;
private Employer employer;
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employer getEmployer() {
return employer;
}
public void setEmployer(Employer employer) {
this.employer = employer;
}
public Employee(String employeeName, Employer employer){
this.employeeName = employeeName;
this.employer = employer;
}
public Object clone() throws CloneNotSupportedException {
Employee employee = (Employee)super.clone();
return employee;
}
}
public class TestShallowClone{
public static void main(String[] args) throws CloneNotSupportedException {
Employer employer = new Employer("Jack", 30);
Employee employee = new Employee("John", employer);
Employee emeClone = (Employee) employee.clone();
emeClone.getEmployer().setEmployerName("Tom");
System.out.println(emeClone.getEmployer().getEmployerName());
// 浅克隆对象的改变影响了被克隆对象System.out.println(employee.getEmployerer().getEmployerName());
System.out.println((employee.getEmployer() == emeClone.getEmployer()) ? ("浅克隆") : ("深克隆"));
}
}
输出:
Tom
Tom
浅克隆
两个引用(employee.getEmployer() 和 emeClone.getEmployer())所指向的对象在堆中一致,互相影响,浅克隆。
class Employer implements Cloneable{
private String employerName;
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmployerName() {
return employerName;
}
public void setEmployerName(String employerName) {
this.employerName = employerName;
}
public Employer(String employerName, int age){
this.employerName = employerName;
this.age = age;
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
class Employee implements Cloneable{
private String employeeName;
private Employer employer;
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public Employer getEmployer() {
return employer;
}
public void setEmployer(Employer employer) {
this.employer = employer;
}
public Employee(String employeeName, Employer employer){
this.employeeName = employeeName;
this.employer = employer;
}
public Object clone() throws CloneNotSupportedException {
Employee employee = (Employee)super.clone();
employee.employer = (Employer)employer.clone();
return employee;
}
}
public class TestDeepClone{
public static void main(String[] args) throws CloneNotSupportedException {
Employer employer = new Employer("Jack", 30);
Employee employee = new Employee("John", employer);
Employee emeClone = (Employee) employee.clone();
emeClone.getEmployer().setEmployerName("Tom");
System.out.println(emeClone.getEmployer().getEmployerName());
// 深克隆对象的改变不影响被克隆对象
System.out.println(employee.getEmployer().getEmployerName());
System.out.println((employee.getEmployer() == emeClone.getEmployer()) ? ("浅克隆") : ("深克隆"));
}
}
输出:
Tom
Jack
深克隆
两个引用(employee.getEmployer() 和 emeClone.getEmployer())所指向的对象在堆中相互独立,互不影响,深克隆。
总结:
1.被克隆的对象必须实现java.lang.Cloneable接口。
2.在克隆对象时,不调用构造函数。
3.浅克隆是在创建好对象副本后通过赋值进行拷贝,如果对象中包含引用类型,那么原始对象和克隆对象都指向相同的堆内存,对克隆对象任何修改都会影响到原始对象;必须使用深克隆,引用类型对象也需实现java.lang.Cloneable接口,重写clone(), 原始对象中clone()方法需将原始对象的引用类型成员赋值为引用对象的clone()。
4.对于基本类型byte,char,boolean,short,int,long,float,double会进行值拷贝,而对引用类型和数组,则是地址拷贝(也叫引用拷贝),就是指在新的对象中声明一个引用,该引用的地址指向被拷贝对象中的对应的成员的地址。
5.emeClone.setEmployeeName(“Hank”) 只是将emeClone的employeeName指向另一个String对象“Hank”,查看employee.getEmployeeName()还是为“John”;java中String对象是不可变的,一旦创建,就不能修改它的值;如果一个类的成员变量是基本类型和String类型,调用Object的clone()是安全的克隆。