将一个对象的引用复制给另外一个对像三个方式:1.直接赋值、2.浅拷贝、3.深拷贝
1.直接赋值:赋值的是引用。
2.浅拷贝定义(shallow clone):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
3.深拷贝(deep clone):被复制对象的所有变量都含有与原来的对象相同的值,把要复制的对象所引用的对象都复制了一遍。
直接赋值例子:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:31
*/
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:06
*/
public class CloneTest {
public static void main(String[] args) {
Student s=new Student("s");
Student ss=s;
ss.setName("ss");
System.out.println("s对象的姓名..."+s.getName());
}
}
结果:
s对象的姓名...ss
结论:直接赋值是对象引用,也就是说多个对象引用同一个,任何一个对象改变引用,那么其他对象的内容跟着变(本例子中,s对象的姓名“s”,被ss对象改变了)
浅拷贝例子:实现Cloneable接口,该接口没有任何方法
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:31
*/
public class Student implements Cloneable{
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//不是重写方法,Cloneable没有任何方法
public Student clone() {
try {
return (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
测试:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:06
*/
public class CloneTest {
public static void main(String[] args) {
Student s=new Student("s");
Student ss=s.clone();
ss.setName("ss");
System.out.println("s对象的姓名..."+s.getName());
}
}
结果:
s对象的姓名...s
ss改变了对象name,但是s对象name没有变。
结论:利用浅拷贝,相当于创建一个对象。但是如果对象里面包含另外一个对象引用呢?结果如何
浅拷贝的复杂对象的例子:
对象Student:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:31
*/
public class Student implements Cloneable{
private String name;
private StudentClass studentClass;//添加了一个对象引用
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudentClass getStudentClass() {
return studentClass;
}
public void setStudentClass(StudentClass studentClass) {
this.studentClass = studentClass;
}
public Student clone() {
try {
return (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
对象StudentClass:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 下午 12:54
*/
public class StudentClass {
/**
* 班级编号
*/
private String number;
public StudentClass(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
测试代码:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:06
*/
public class CloneTest {
public static void main(String[] args) {
Student s = new Student("s");
s.setStudentClass(new StudentClass("1班"));
Student ss = s.clone();
ss.setName("ss");
ss.getStudentClass().setNumber("2班");
System.out.println("s对象的姓名..." + s.getName());
System.out.println("s对象的班级..." + s.getStudentClass().getNumber());
}
}
结果:
s对象的姓名...s
s对象的班级...2班
s对象的班级编号,还是被ss对象改变了。如果面对复杂的对象中(对象嵌套对象,怎么办?)
深度拷贝:
Student对象:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:31
*/
public class Student implements Cloneable {
private String name;
private StudentClass studentClass;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public StudentClass getStudentClass() {
return studentClass;
}
public void setStudentClass(StudentClass studentClass) {
this.studentClass = studentClass;
}
public Student clone() {
Student s = null;
try {
s = (Student) super.clone();
s.studentClass = s.getStudentClass().clone();//将引用的对象也加上
return s;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
StudentClass对象:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 下午 12:54
*/
public class StudentClass implements Cloneable {
/**
* 班级编号
*/
private String number;
public StudentClass(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public StudentClass clone() {
try {
return (StudentClass) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
测试:
/**
* Description:
* User: lc
* Date: 2017/10/6 0006
* Time: 上午 11:06
*/
public class CloneTest {
public static void main(String[] args) {
Student s = new Student("s");
s.setStudentClass(new StudentClass("1班"));
Student ss = s.clone();
ss.setName("ss");
ss.getStudentClass().setNumber("2班");
System.out.println("s对象的姓名..." + s.getName());
System.out.println("s对象的班级..." + s.getStudentClass().getNumber());
System.out.println("s对象的hsahCode..."+s.toString());
System.out.println("ss对象的hsahCode..."+ss.toString());
}}
测试结果:
s对象的姓名...s
s对象的班级...1班
s对象的地址...object.objectClone.Student@28d93b30
ss对象的地址...object.objectClone.Student@1b6d3586
ss对象的改变,没有影响到s对象.两个不同对象,地址不一样
总结:
1. 需要实现Cloneable接口。Cloneable接口里面没任何方法。会抛出 CloneNotSupportedException.重写clone方法(因为Object是任何类的父类)
2.Object的clone方法是protect,本地方法(native).
3.如果对象嵌套对象,很复杂的情况,用深度拷贝,不合适,这样时候需要用序列化以及反序列化。
备注:继承自java.lang.Object类的clone()方法是浅复制。
克隆与new的区别:
1.clone可以保存当时对象的状态。而new只能进行初始化状态。
2.clone调用的是本地方法,速度更快