欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java对象的浅度clone和深度clone 博客分类: javajust do itmore and more javaclonedeep克隆拷贝 

程序员文章站 2024-03-26 12:12:11
...

 

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

 

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