`

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提供了两种主要的克隆方式:浅度克隆(Shallow Clone)和深度克隆(Deep Clone)。理解这两种克隆的区别对于优化内存管理和复制复杂对象至关重要。 **浅度克隆(Shallow Clone)** 浅度克隆仅仅复制了对象本身...

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

    在C#编程中,了解深度复制和浅度复制的概念至关重要,因为它们直接影响到对象的复制行为,特别是当处理包含复杂数据结构的对象时。本文将详细解释这两种复制方式,并通过一个实例来展示它们的区别。 首先,让我们...

    prototypeAndCreate.zip

    总结起来,"prototypeAndCreate.zip"中的内容可能是关于Java编程中原型模式的实践,包括浅度和深度克隆的实现,以及如何在创建车辆实例时应用这些概念。这些示例代码对于理解原型模式和创建模式在实际开发中的运用...

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

    在Java编程语言中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种不同的对象复制方式,它们涉及到内存中数据的复制和引用的处理。理解这两种拷贝方式对于开发过程中正确管理和操作对象至关重要。 浅拷贝,又...

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

    ***中深度复制和浅度复制是编程中常见的概念,尤其是在涉及到对象复制和内存管理的场景中。为了理解这两个概念,首先我们需要明确值类型和引用类型的区别。 值类型直接存储其数据,而在.NET框架中包括了所有的基本...

    java-6个机制.doc

    Java的克隆机制通过`Object.clone()`方法实现,该方法位于`java.lang.Object`类中。 **1.2 实现要求** - **实现`Cloneable`接口**:被克隆的类必须实现`Cloneable`接口,表明该类支持克隆操作。 - **重写`clone()`...

    javascript克隆对象深度介绍

    而引用类型,如数组和对象,是按引用传递的,也就是说,当你传递一个对象时,实际上是传递了该对象在内存中的地址,而不是对象本身。 对象克隆分为两种:浅度克隆和深度克隆。 1. 浅度克隆:在浅度克隆中,只复制...

    UNDERSCORE_jquery:查看UNDERSCORE和jquery

    2. **实用函数**:包括`_.uniqueId`用于生成唯一ID,`_.clone`用于深度或浅度克隆对象,`_.isEqual`用于比较两个值是否相等,以及`_.throttle`和`_.debounce`用于节流和防抖,优化性能。 3. **对象操作**:...

Global site tag (gtag.js) - Google Analytics