您的位置:首页 > 编程语言 > Java开发

Java(对象的深克隆和浅克隆)

2014-04-08 23:18 417 查看
浅克隆:复制的对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅克隆仅仅复制所考虑的对象,而不复制它所引用的对 象

深克隆:复制的对象的所有变量都含有与原来对象相同的值,那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象,换言之,深克隆复制的对象 所引用的所有对象都复制了一份。

浅克隆实例:

public class Test {
public static void main(String[] args) throws Exception {
Student student = new Student();
student.setAge(20);
student.setName("zhangsan");

Student student2 = (Student)student.clone();
System.out.println(student2.getAge());
System.out.println(student2.getName());
}
}

/**
* 必须实现Cloneable才能支持对象的克隆
* @author yinhao
*
*/
class Student implements Cloneable{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

@Override
public Object clone() throws CloneNotSupportedException {
//需要调用super.clone()返回clone对象,super.clone()是一个native方法,会进行检测旧对象属性,新对象的内存地址分配等操作
Object object = super.clone();
return object;
}
}


深克隆实例:

public class Test2 {
public static void main(String[] args) throws Exception {
Teacher teacher = new Teacher();
teacher.setAge(40);
teacher.setName("teacher wang");

Student2 student = new Student2();
student.setAge(20);
student.setName("zhangsan");
student.setTeacher(teacher);

System.out.println(student.getAge());
System.out.println(student.getName());
System.out.println(student.getTeacher());

System.out.println("-----------------------------");

Student2 student2 = (Student2)student.clone();

System.out.println(student2.getAge());
System.out.println(student2.getName());
System.out.println(student2.getTeacher());//新克隆的Teacher对象

}
}

/**
* 必须实现Cloneable才能支持对象的克隆
* @author yinhao
*
*/
class Student2 implements Cloneable{
private int age;
private String name;
private Teacher teacher;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
//需要调用super.clone()返回clone对象,super.clone()是一个native方法,会进行检测旧对象属性并一一复制,新对象的内存地址分配等操作
Student2 student2 = (Student2)super.clone();
//将新克隆的Student2对象中的Teacher对象再次克隆,作为新克隆的Student2对象中的Teacher对象
student2.setTeacher((Teacher)student2.getTeacher().clone());

return student2;
}
}

class Teacher implements Cloneable{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

@Override
public Object clone() throws CloneNotSupportedException {
//需要调用super.clone()返回clone对象,super.clone()是一个native方法,会进行检测旧对象属性并一一复制,新对象的内存地址分配等操作
Object object = super.clone();
return object;
}

}


在Java中,深克隆一个对象,常常可以使对象实现Serializable接口,然后把对象(实际上是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

这样做的前提是对象以及对象内部所有引用到的对象都是可序列化的,否则就需要仔细考虑那些不可序列化的对象是否可设成transient,从而将之排除在复制过程之外。

使用对象的序列化实现深克隆实例:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
* 使用序列化,深克隆 需要实现Serializable接口
* Java中的序列化,不仅会序列化对象,也会序列化对象中引用的其他对象,如果引用没有被transient修饰的话
* @author yinhao
*
*/
public class Test3 {
public static void main(String[] args) throws Exception {
Teacher3 teacher3 = new Teacher3();
teacher3.setAge(40);
teacher3.setName("teacher zhang");

Student3 student1 = new Student3();
student1.setAge(20);
student1.setName("zhangsan");
student1.setTeacher(teacher3);

System.out.println(student1.getAge());
System.out.println(student1.getName());
System.out.println(student1.getTeacher());
System.out.println(student1.getTeacher().getAge());
System.out.println(student1.getTeacher().getName());

System.out.println("--------------------------------------");

Student3 student2 = student1.deepClone();
System.out.println(student2.getAge());
System.out.println(student2.getName());
System.out.println(student2.getTeacher());
System.out.println(student2.getTeacher().getAge());
System.out.println(student2.getTeacher().getName());

}
}

class Student3 implements Serializable {
private int age;
private String name;
private Teacher3 teacher;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Teacher3 getTeacher() {
return teacher;
}

public void setTeacher(Teacher3 teacher) {
this.teacher = teacher;
}

public Student3 deepClone() throws Exception {
// 将对象序列化到字节数组输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
byteArrayOutputStream);
objectOutputStream.writeObject(this);
// 将对象从字节数组输出流读出
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(
byteArrayInputStream);
return (Student3)objectInputStream.readObject();
}
}

class Teacher3 implements Serializable {
private int age;
private String name;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}


关于实现Serializable接口的类中的serialVersionUID的问题:

1.如果你的对象在序列化存到硬盘上后,可是后来你却更改了类的属性(增加或删除),当你反序列化时,就会出现异常,类型不匹配。

2.但是当serialVersionUID相同时,假设你又增加了一个属性,在反序列化时,它就会将新增的属性根据其类型设置为该类型的默认值,避开版本不兼容问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: