`

Java对象的浅度clone和深度clone

阅读更多

 

最近在研究Java的深度拷贝,浏览了很多网友的博客,发现一个共同点,就是csdn,博客园,iteye上的文章都是如出一辙,互相拷贝,借鉴我就不说了,你发个错的在上面,这就是你的不对了,你发上去不就是让人看的么?这样做岂不是误人子弟?所以现在小弟决定自己写个小记,虽然内容不多,但是容易懂,代码都是经过我自己编码运行的,没有问题。好了,废话不多说了,开始正文吧

 

1.浅度拷贝和深度拷贝概念

⑴浅度拷贝(浅克隆)

被拷贝对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。也就是说浅度拷贝仅仅拷贝所引用的对象,而不拷贝它所引用的对象,这个我在下面的例子中,大家可以看出来。

 

⑵深复制拷贝(深克隆)

被拷贝对象的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向被拷贝过的新对象,而不再是原有的那些被引用的对象,也就是说深度拷贝把要拷贝的对象所有引用的对象都拷贝了一遍,下面的例子也会体现出来。

 

2.Java的clone()方法

⑴clone方法将对象拷贝了一份并返回给调用者。一般而言,clone()方法满足:

①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象

②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样

③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

 

⑵Java中对象的克隆

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 

②在派生类中覆盖基类的clone()方法,并声明为public。 

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

④在派生类中实现Cloneable接口。

 

 

下面看个例子:(深度拷贝一般属性)

class Student implements Cloneable {

 

private String name;// 一般属性。

private int age;// 一般属性。

 

Student(String name, int age) {

this.name = name;

this.age = age;

}

 

public Object clone() {

Student o = null;

 

try {

o = (Student) super.clone();

} catch (CloneNotSupportedException e) {

System.out.println(e.toString());

}

return o;

}

 

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 class TEST {

 

public static void main(String[] args) {

 

Student s1 = new Student("old", 18);

 

Student s2 = (Student) s1.clone();

 

System.out.println("对象中的一般属性");

 

System.out.println("修改之前");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

s2.setName("new");

s2.setAge(23);

 

System.out.println("修改之后");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

}

}

 

 

打印的结果:

 

对象中的一般属性

修改之前

name=old,age=18

name=old,age=18

修改之后

name=old,age=18

name=new,age=23

 

又一个例子(深度拷贝一般属性,浅度拷贝引用属性private Professor p;中的p是引用一个对象,

即使深度拷贝了Student中的属性,但是他这个属性依然是引用的拷贝,而这个引用却是指向同一个

对象,下面子的例子可以看出结果)

class Professor {

 

private String name;

private int age;

 

Professor(String name, int age) {

this.name = name;

this.age = 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 Student implements Cloneable {

 

private String name;// 一般属性。

private int age;// 一般属性。

private Professor p;

 

Student(String name, int age, Professor p) {

this.name = name;

this.age = age;

this.p = p;

}

 

public Object clone() {

Student o = null;

 

try {

o = (Student) super.clone();

} catch (CloneNotSupportedException e) {

System.out.println(e.toString());

}

return o;

}

 

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 Professor getP() {

return p;

}

 

public void setP(Professor p) {

this.p = p;

}

 

}

 

public class TEST {

 

public static void main(String[] args) {

 

Professor p = new Professor("老虎", 50);

Student s1 = new Student("old", 18, p);

 

Student s2 = (Student) s1.clone();

 

System.out.println("看对象中的一般属性");

System.out.println("-------修改之前-------");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

s2.setName("new");

s2.setAge(23);

 

System.out.println("----=--修改之后-------");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

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

System.out.println("看对象中的引用属性");

 

System.out.println("-------修改之前------");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

s2.getP().setName("hahahaha");

 

System.out.println("-------修改之后-----");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

}

}

 

 

打印的结果:

 

看对象中的一般属性

-------修改之前-------

name=old,age=18

name=old,age=18

----=--修改之后-------

name=old,age=18

name=new,age=23

==================================

看对象中的引用属性

-------修改之前------

叫兽的name=老虎

叫兽的name=老虎

-------修改之后-----

叫兽的name=hahahaha

叫兽的name=hahahaha

 

又一个例子(深度拷贝一般属性,深度拷贝引用属性private Professor p;这个时候需要在Student中

的clone对象中去调用Professor的克隆方法,此时Professor需要实现Cloneable)

class Professor implements Cloneable{

 

private String name;

private int age;

 

Professor(String name, int age) {

this.name = name;

this.age = 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

protected Object clone() throws CloneNotSupportedException {

// TODO Auto-generated method stub

return super.clone();

}

}

 

class Student implements Cloneable {

 

private String name;// 一般属性。

private int age;// 一般属性。

private Professor p;

 

Student(String name, int age, Professor p) {

this.name = name;

this.age = age;

this.p = p;

}

 

public Object clone() {

Student o = null;

 

try {

o = (Student) super.clone();

} catch (CloneNotSupportedException e) {

System.out.println(e.toString());

}

try {

o.p = (Professor) o.p.clone();

} catch (CloneNotSupportedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return o;

}

 

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 Professor getP() {

return p;

}

 

public void setP(Professor p) {

this.p = p;

}

 

}

 

public class TEST {

 

public static void main(String[] args) {

 

Professor p = new Professor("老虎", 50);

Student s1 = new Student("old", 18, p);

 

Student s2 = (Student) s1.clone();

 

System.out.println("看对象中的一般属性");

System.out.println("-------修改之前-------");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

s2.setName("new");

s2.setAge(23);

 

System.out.println("----=--修改之后-------");

System.out.println("name=" + s1.getName() + "," + "age=" + s1.getAge());

System.out.println("name=" + s2.getName() + "," + "age=" + s2.getAge());

 

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

System.out.println("看对象中的引用属性");

 

System.out.println("-------修改之前------");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

s2.getP().setName("hahahaha");

 

System.out.println("-------修改之后-----");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

}

}

 

打印的结果:

 

看对象中的一般属性

-------修改之前-------

name=old,age=18

name=old,age=18

----=--修改之后-------

name=old,age=18

name=new,age=23

==================================

看对象中的引用属性

-------修改之前------

叫兽的name=老虎

叫兽的name=老虎

-------修改之后-----

叫兽的name=老虎

叫兽的name=hahahaha

 

最后一个例子(用流的方式实现深度拷贝,很简单,不详细说明了,不过要注意要流化对象,

必须要实现Serializable接口)

class Professor implements Cloneable, Serializable {

 

/**

*/

private static final long serialVersionUID = -9034223179100535667L;

private String name;

private int age;

 

Professor(String name, int age) {

this.name = name;

this.age = 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;

}

 

protected Object clone() throws CloneNotSupportedException {

// TODO Auto-generated method stub

return super.clone();

}

 

public Object deepClone(Object o) {

 

Object obj = null;

 

// 将对象写到流里

ByteArrayOutputStream bo = new ByteArrayOutputStream();

ObjectOutputStream oo = null;

 

// 从流里读出来

ObjectInputStream oi = null;

ByteArrayInputStream bi = null;

try {

oo = new ObjectOutputStream(bo);

oo.writeObject(o);

 

oo.flush();

oo.close();

bi = new ByteArrayInputStream(bo.toByteArray());

oi = new ObjectInputStream(bi);

obj = oi.readObject();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} finally {

try {

// oi.close();

// oo.close();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

}

 

return obj;

}

 

}

 

class Student implements Cloneable {

 

private String name;// 常量对象。

private int age;

private Professor p;

 

Student(String name, int age, Professor p) {

this.name = name;

this.age = age;

this.p = p;

}

 

public Object clone() {

Student o = null;

 

try {

o = (Student) super.clone();

} catch (CloneNotSupportedException e) {

System.out.println(e.toString());

}

o.p = (Professor) o.getP().deepClone(p);

return o;

}

 

/**

* @return the name

*/

public String getName() {

return name;

}

 

/**

* @param name

*            the name to set

*/

public void setName(String name) {

this.name = name;

}

 

/**

* @return the age

*/

public int getAge() {

return age;

}

 

/**

* @param age

*            the age to set

*/

public void setAge(int age) {

this.age = age;

}

 

/**

* @return the p

*/

public Professor getP() {

return p;

}

 

/**

* @param p

*            the p to set

*/

public void setP(Professor p) {

this.p = p;

}

 

}

 

public class TEST04 {

 

public static void main(String[] args) {

 

Professor p = new Professor("old", 50);

 

Student s1 = new Student("old", 18, p);

 

Student s2 = (Student) s1.clone();

 

Professor objP = (Professor) p.deepClone(p);

 

System.out.println("修改之前");

System.out.println("name=" + p.getName() + ", age =" + p.getAge());

System.out.println("name=" + objP.getName() + ", age =" + objP.getAge());

 

p.setName("hahaha");

objP.setAge(100);

 

System.out.println("修改之后");

System.out.println("name=" + p.getName() + ", age =" + p.getAge());

System.out.println("name=" + objP.getName() + ", age =" + objP.getAge());

 

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

System.out.println("看对象中的引用属性");

 

System.out.println("-------修改之前------");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

s2.getP().setName(".......");

 

System.out.println("-------修改之后-----");

System.out.println("叫兽的name=" + s1.getP().getName());

System.out.println("叫兽的name=" + s2.getP().getName());

 

}

}

 

打印的结果:

 

修改之前

name=old, age =50

name=old, age =50

修改之后

name=hahaha, age =50

name=old, age =100

==================================

看对象中的引用属性

-------修改之前------

叫兽的name=hahaha

叫兽的name=old

-------修改之后-----

叫兽的name=hahaha

叫兽的name=.......

 

自己也是刚刚接触,如果有什么问题,请各位及时提出,并批评指正。

分享到:
评论

相关推荐

    基于java实现浅度爬虫应用

    基于java实现浅度爬虫应用,是我学习java来练练手的,java爬虫基础入门的学生可以考虑参考一下

    c#深度复制浅度复制

    c#深度复制浅度复制

    C#中深度复制和浅度复制详解

    本文章主要是讲解C# 语言编程中,深度复制和浅度复制,下面我将通过一个实例进行讲解。在实例开发之前,我们得先知道深度复制是什么和浅度复制是什么,它们之间的区别又是什么,下面将为大家一一揭晓。 1.深度复制是...

    实例详解vue.js浅度监听和深度监听及watch用法

    主要介绍了vue.js浅度监听和深度监听及watch用法,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧

    Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍

    主要介绍了Java中的深拷贝(深复制)和浅拷贝(浅复制)介绍,需要的朋友可以参考下

    解析JAVA深度克隆与浅度克隆的区别详解

    本篇文章是对JAVA深度克隆与浅度克隆的区别进行了详细的分析介绍,需要的朋友参考下

    浅度探索C++对象模型bin3.ppt

    浅度探索C++对象模型bin3.ppt

    ASP.NET深度复制和浅度复制分析

    本文深入浅出的分析了ASP.NET深度复制和浅度复制。分享给大家供大家参考。具体分析如下: 之前一直没有搞清楚深度复制和浅度复制的区别到底在哪里,今天彻底把这个东西弄懂了,写出来与到家共勉。 如果大家不懂值...

    ajax从基础学起

    内容有:1.ajax入门的三个好例子,很值得学习和借鉴的地方,循序渐进的学习方法 2.ajax的方法从零开始讲起,如何实现,简单明了 3.java的重点介绍,不是纯粹的说说java的语法,既有浅度也有深度,我认为学...

    javascript克隆对象深度介绍

    克隆或者拷贝分为2种: 浅度克隆:基本类型为值传递,对象仍为引用传递。 深度克隆:所有元素或属性均完全克隆,并于原引用类型完全独立,即,在后面修改对象的属性的时候,原对象不会被修改。 代码如下: function ...

    网络语言浅度研究报告.doc

    网络语言浅度研究报告.doc

    JavaScript Array对象详解

    本文介绍了Js的Array 数组对象,具体内容如下 目录 1. 介绍:介绍 Array 数组对象的说明、定义方式以及属性。...4. 实际操作:对 Array 进行示例操作:索引、for遍历、浅度复制、深度复制等操作。  一. 介绍

    prototypeAndCreate.zip

    原型实例代码示例 浅度克隆、深度克隆 创建模式代码示例 组装车辆

    JRE Hack 浅度研究

    NULL 博文链接:https://lzy.iteye.com/blog/407956

    MyEclipse浅度优化方法

    大家是否觉得MyEclipse启动很慢,那么来看一下吧,如果谁有其他的优化方法,欢迎交流!

    浅度解析C++运算符重载

    踏入C++的世界已经两年了,但一直在黑夜中前行,最近看到了由Lostmouse 译的Scott Meyers的著作《EffectiveC++》的中文版电子书,犹如一盏指路明灯,照亮了我前进的路。这本书由lians制作,由save 修订。...

    煤样粒径对煤低温氧化影响的实验研究

    同时依据基于耗氧量建立的数学模型来测算煤低温氧化时不同粒径煤样活化能和指前因子等动力学参数,结果表明不同粒径煤样低温氧化耗氧速率变化分为缓慢耗氧、浅度耗氧和深度耗氧等三个阶段,在实验条件下煤样粒径小于0....

Global site tag (gtag.js) - Google Analytics