复制一个对象 java_Java如何完全复制一个对象

Java里的clone分为:

** A:浅复制(浅克隆): **浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

B:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。

Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点:

1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。

2.在派生类的clone()方法中,调用super.clone()。

3.在派生类中实现Cloneable接口。 Object类里的clone方法是浅复制(浅克隆)

下面这段只是引言。具体示例请往下翻。

对于一个新手而言,让你复制一个对象,你可能觉得很简单:

class Student {

private int number;

public int getNumber() {

return number;

}

public void setNumber(int number) {

this.number = number;

}

}

public class Test {

public static void main(String args[]) {

Student stu1 = new Student();

stu1.setNumber(12345);

Student stu2 = stu1;

System.out.println("学生1:" + stu1.getNumber());

System.out.println("学生2:" + stu2.getNumber());

}

}

打印结果:

学生1:12345

学生2:12345

这里我们自定义了一个学生类,该类只有一个number字段。

我们新建了一个学生实例,然后将该值赋值给stu2实例。(Student stu2 = stu1;)

再看看打印结果,作为一个新手,拍了拍胸腹,对象复制不过如此,

难道真的是这样吗?

我们试着改变stu2实例的number字段,再打印结果看看:

stu2.setNumber(54321);

System.out.println("学生1:" + stu1.getNumber());

System.out.println("学生2:" + stu2.getNumber());

打印结果:

学生1:54321

学生2:54321

完了,出问题了。为什么我改变了stu2的值,stu1也跟着改变了呢?

原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2。其实,stu1和stu2在堆内存中指向的是同一个对象。如图:

c3fbb9ea855f?from=groupmessage

正文开始

那么,怎样才能达到复制一个对象呢?

是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。

该方法的签名是:

protected native Object clone() throws CloneNotSupportedException;

因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。

要想对一个对象进行复制,就需要对clone方法覆盖。

一般步骤是(浅复制):

被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)

覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

下面对上面那个方法进行改造:

class Student implements Cloneable{

private int number;

public int getNumber() {

return number;

}

public void setNumber(int number) {

this.number = number;

}

@Override

public Object clone() {

Student stu = null;

try{

stu = (Student)super.clone();

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}

return stu;

}

}

public class Test {

public static void main(String args[]) {

Student stu1 = new Student();

stu1.setNumber(12345);

Student stu2 = (Student)stu1.clone();

System.out.println("学生1:" + stu1.getNumber());

System.out.println("学生2:" + stu2.getNumber());

stu2.setNumber(54321);

System.out.println("学生1:" + stu1.getNumber());

System.out.println("学生2:" + stu2.getNumber());

}

}

打印结果:

学生1:12345

学生2:12345

学生1:12345

学生2:54321

到这里,一个简单的浅复制就OK了。

2.深复制(深Clone)例子:

public class DeepCloneTest {

public static void main(String[] args) throws Exception {

// teacher对象将不被clone出来的Student对象共享.

Teacher teacher = new Teacher();

teacher.setAge(40);

teacher.setName("Teacher zhang");

Student student1 = new Student();

student1.setAge(20);

student1.setName("zhangsan");

student1.setTeacher(teacher);

// 复制出来一个对象student2

Student student2 = (Student) student1.clone();

System.out.println(student2.getAge());

System.out.println(student2.getName());

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

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

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

// 修改student2的引用对象

student2.getTeacher().setAge(50);

student2.getTeacher().setName("Teacher Li");

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

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

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

}

}

class Teacher implements Cloneable {

public int age;

public 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 {

return super.clone();

}

}

class Student implements Cloneable {

public int age;

public String name;

public 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 {

Student student = (Student) super.clone();

// 将引用的对象teacher也clone下

student.setTeacher((Teacher) (student.getTeacher().clone()));

return student;

}

}

打印结果:

20

zhangsan

~~~~~~~~~~~~~~~~~~~~~~

40

Teacher zhang

~~~~~~~~~~~~~~~~~~~~~~

40

Teacher zhang

3.利用序列化来做深复制

把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程。**应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。利用这个特性,可以做深拷贝 。

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

//利用序列化来做深复制

//深clone

public class DeepCloneTest

{

public static void main(String[] args) throws Exception

{

// teacher对象将不被clone出来的Student对象共享.

Teacher teacher = new Teacher();

teacher.setAge(40);

teacher.setName("Teacher zhang");

Student student1 = new Student();

student1.setAge(20);

student1.setName("zhangsan");

student1.setTeacher(teacher);

// 复制出来一个对象student2

Student student2 = (Student) student1.deepCopy();

System.out.println(student2.getAge());

System.out.println(student2.getName());

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

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

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

// 修改student2的引用对象

student2.getTeacher().setAge(50);

student2.getTeacher().setName("Teacher Li");

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

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

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

}

}

class Teacher implements Serializable

{

private static final long serialVersionUID = -8834559347461591191L;

public int age;

public 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;

}

}

class Student implements Serializable

{

// serialVersionUID

// 如果你的对象序列化后存到硬盘上面后,可是后来你却更改了类的field(增加或减少或改名),当你

// 反序列化时,就会出现Exception的,这样就会造成不兼容性的问题。

// 但当serialVersionUID相同时,它就会将不一样的field以type的

// 缺省值赋值(如int型的是0,String型的是null等),这个可以避开不兼容性的问题。

// 所以最好给serialVersionUID赋值

private static final long serialVersionUID = 7991552226614088458L;

public int age;

public String name;

public 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;

}

public Object deepCopy() throws Exception

{

// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

// 所以利用这个特性可以实现对象的深拷贝。

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(this);

// 将流序列化成对象

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bis);

return ois.readObject();

}

}

打印结果:

20

zhangsan

~~~~~~~~~~~~~~~~~~~~~~

40

Teacher zhang

~~~~~~~~~~~~~~~~~~~~~~

40

Teacher zhang

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值