1.进行浅拷贝时,只是复制原始数据类型的值,则可以通过覆盖Clone方法来达到。另外,在进行浅拷贝的时候,还要注意,成员对象中不应该要有引用类型,如果有引用类型,那么,进行了浅拷贝之后,两个对象将会共享成员引用所指向的对象,这会出现问题。所以,在这种情况下,干脆直接使用深拷贝,避免问题出现。2.对于深拷贝,也就是完全将对象的内容复制一份,则使用序列化来实现,也是为了避免覆盖Clone。
浅拷贝的例子:
这个例子,只是复制成员的值,成员的类型都是原始数据类型,不包含引用类型:
public class CloneTest1 { public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
student1.setName("ZhangSan");
student1.setAge(20); Student student2 = new Student();
student2 = (Student) student1.clone(); System.out.println("拷贝得到的信息");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println("-------------"); // 修改第二个对象的信息
student2.setName("LiSi");
student2.setAge(25); System.out.println("修改第二个对象的属性为lisi,25后:");
System.out.println("第一个对象:");
System.out.println(student1.getName());
System.out.println(student1.getAge());
System.out.println("第二个对象:");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println("-------------"); // 说明两个引用student1和student2指向的是不同的对象 }
} class Student implements Cloneable {
private String name;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public Student clone() throws CloneNotSupportedException {
// 注意此处要把protected改为public Student student = (Student)super.clone(); return student;
}
}
输出:
拷贝得到的信息
ZhangSan
20
-------------
修改第二个对象的属性为lisi,25后:
第一个对象:
ZhangSan
20
第二个对象:
LiSi
25
-------------
浅拷贝例子2:
这个例子中,成员的类型,有引用类型
public class CloneTest2 {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("Teacher Zhang");
teacher.setAge(40); StudentNew student1 = new StudentNew();
student1.setName("ZhangSan");
student1.setAge(20);
student1.setTeacher(teacher); StudentNew student2 = (StudentNew) student1.clone();
System.out.println("拷贝得到的信息");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getTeacher().getName());
System.out.println(student2.getTeacher().getAge());
System.out.println("-------------"); // 修改老师的信息
teacher.setName("Teacher Zhang has changed");
System.out.println(student1.getTeacher().getName());
System.out.println(student2.getTeacher().getName()); // 两个引用student1和student2指向不同的两个对象
// 但是两个引用student1和student2中的两个teacher引用指向的是同一个对象
// 所以说明是浅拷贝
} } class Teacher {
private String name;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} } class StudentNew implements Cloneable {
private String name;
private int age;
private Teacher teacher; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public Teacher getTeacher() {
return teacher;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} @Override
public StudentNew clone() throws CloneNotSupportedException {
StudentNew object = (StudentNew) super.clone();
return object;
} }
输出结果:
拷贝得到的信息
ZhangSan
20
Teacher Zhang
40
-------------
Teacher Zhang has changed
Teacher Zhang has changed
解析:
Student1和Student2,是两个对象,执行浅拷贝之后,两个的成员的值是相等的。如果里面包含了引用类型的成员,那么,它们是指向同一个对象的。比如,引用类型teacher成员。因为指向同一个对象,所以对teacher的修改,会同时影响到Student1,Student2.这会出现很多意料不到的问题。对于这种情况,我倾向于,使用序列化,做一个深拷贝。
深拷贝,使用序列化实现的深拷贝:
使用序列化实现深拷贝,优点是,不用覆盖Clone(覆盖Clone方法,把握不好,会出现各种问题);缺点是:类成员如果有类类型,则都要实现序列化接口,这样才可以进行序列化,比如下面的例子。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; public class JavaDeepClone { public static void main(String[] args) {
// (1) create a Person object named Al
Address address = new Address("305 West Fern Avenue", "Palmer", "Alaska");
Person al = new Person("Al", "Alexander", address); // (2) make a deep clone of Al
Person neighbor = (Person) deepClone(al); // (3) modify the neighbor's attributes
neighbor.firstName = "Martha";
neighbor.lastName = "Stewart"; // (4) show that it all worked
System.out.print(neighbor);
System.out.println(al);
} /**
* This method makes a "deep clone" of any object it is given.
*/
public static Object deepClone(Object object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
} /**
* These classes implement Serializable so we can write them out and read them back in as a stream
* of bytes.
*/
class Person implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4112183016776552816L;
String firstName, lastName;
Address address; public Person(String firstName, String lastName, Address address) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
} public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("First Name: " + firstName + "\n");
sb.append("Last Name: " + lastName + "\n");
sb.append("Street: " + address.street + "\n");
return sb.toString();
}
} class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3711035200324594412L;
String street, city, state; public Address(String street, String city, String state) {
this.street = street;
this.city = city;
this.state = state;
}
}
输出结果:
First Name: Martha
Last Name: Stewart
Street: 305 West Fern Avenue
First Name: Al
Last Name: Alexander
Street: 305 West Fern Avenue
引用:
http://www.cnblogs.com/mengdd/archive/2013/02/20/2917971.html
http://alvinalexander.com/java/java-deep-clone-example-source-code