Java对象的浅度clone和深度clone

45 篇文章 0 订阅
28 篇文章 0 订阅

 

最近在研究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=.......

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值