1.进行浅拷贝时,只是复制原始数据类型的值,则可以通过覆盖Clone方法来达到。另外,在进行浅拷贝的时候,还要注意,成员对象中不应该要有引用类型,如果有引用类型,那么,进行了浅拷贝之后,两个对象将会共享成员引用所指向的对象,这会出现问题。所以,在这种情况下,干脆直接使用深拷贝,避免问题出现。2.对于深拷贝,也就是完全将对象的内容复制一份,则使用序列化来实现,也是为了避免覆盖Clone。

  浅拷贝的例子:

这个例子,只是复制成员的值,成员的类型都是原始数据类型,不包含引用类型:

public class CloneTest1 {

  public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
student1.setName("ZhangSan");
student1.setAge(20); Student student2 = new Student();
student2 = (Student) student1.clone(); System.out.println("拷贝得到的信息");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println("-------------"); // 修改第二个对象的信息
student2.setName("LiSi");
student2.setAge(25); System.out.println("修改第二个对象的属性为lisi,25后:");
System.out.println("第一个对象:");
System.out.println(student1.getName());
System.out.println(student1.getAge());
System.out.println("第二个对象:");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println("-------------"); // 说明两个引用student1和student2指向的是不同的对象 }
} class Student implements Cloneable {
private String name;
private int 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
public Student clone() throws CloneNotSupportedException {
// 注意此处要把protected改为public Student student = (Student)super.clone(); return student;
}
}

 输出:

拷贝得到的信息
ZhangSan
20
-------------
修改第二个对象的属性为lisi,25后:
第一个对象:
ZhangSan
20
第二个对象:
LiSi
25
-------------

浅拷贝例子2:

这个例子中,成员的类型,有引用类型

public class CloneTest2 {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("Teacher Zhang");
teacher.setAge(40); StudentNew student1 = new StudentNew();
student1.setName("ZhangSan");
student1.setAge(20);
student1.setTeacher(teacher); StudentNew student2 = (StudentNew) student1.clone();
System.out.println("拷贝得到的信息");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getTeacher().getName());
System.out.println(student2.getTeacher().getAge());
System.out.println("-------------"); // 修改老师的信息
teacher.setName("Teacher Zhang has changed");
System.out.println(student1.getTeacher().getName());
System.out.println(student2.getTeacher().getName()); // 两个引用student1和student2指向不同的两个对象
// 但是两个引用student1和student2中的两个teacher引用指向的是同一个对象
// 所以说明是浅拷贝
} } class Teacher {
private String name;
private int 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 StudentNew implements Cloneable {
private String name;
private int age;
private Teacher teacher; 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 Teacher getTeacher() {
return teacher;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} @Override
public StudentNew clone() throws CloneNotSupportedException {
StudentNew object = (StudentNew) super.clone();
return object;
} }

  输出结果:

拷贝得到的信息
ZhangSan
20
Teacher Zhang
40
-------------
Teacher Zhang has changed
Teacher Zhang has changed

解析:

Student1和Student2,是两个对象,执行浅拷贝之后,两个的成员的值是相等的。如果里面包含了引用类型的成员,那么,它们是指向同一个对象的。比如,引用类型teacher成员。因为指向同一个对象,所以对teacher的修改,会同时影响到Student1,Student2.这会出现很多意料不到的问题。对于这种情况,我倾向于,使用序列化,做一个深拷贝。

深拷贝,使用序列化实现的深拷贝:

使用序列化实现深拷贝,优点是,不用覆盖Clone(覆盖Clone方法,把握不好,会出现各种问题);缺点是:类成员如果有类类型,则都要实现序列化接口,这样才可以进行序列化,比如下面的例子。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; public class JavaDeepClone { public static void main(String[] args) {
// (1) create a Person object named Al
Address address = new Address("305 West Fern Avenue", "Palmer", "Alaska");
Person al = new Person("Al", "Alexander", address); // (2) make a deep clone of Al
Person neighbor = (Person) deepClone(al); // (3) modify the neighbor's attributes
neighbor.firstName = "Martha";
neighbor.lastName = "Stewart"; // (4) show that it all worked
System.out.print(neighbor);
System.out.println(al);
} /**
* This method makes a "deep clone" of any object it is given.
*/
public static Object deepClone(Object object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
} /**
* These classes implement Serializable so we can write them out and read them back in as a stream
* of bytes.
*/
class Person implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4112183016776552816L;
String firstName, lastName;
Address address; public Person(String firstName, String lastName, Address address) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
} public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("First Name: " + firstName + "\n");
sb.append("Last Name: " + lastName + "\n");
sb.append("Street: " + address.street + "\n");
return sb.toString();
}
} class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3711035200324594412L;
String street, city, state; public Address(String street, String city, String state) {
this.street = street;
this.city = city;
this.state = state;
}
}

输出结果:

First Name: Martha
Last Name: Stewart
Street: 305 West Fern Avenue
First Name: Al
Last Name: Alexander
Street: 305 West Fern Avenue

引用:

http://www.cnblogs.com/mengdd/archive/2013/02/20/2917971.html

http://alvinalexander.com/java/java-deep-clone-example-source-code

Item 11 谨慎地覆盖Clone的更多相关文章

  1. 第11条:谨慎地覆盖clone

    Clone提供一种语言之外的机制:无需调用构造器就可以创建对象. 它的通用约定非常弱: 创建和返回该对象的一个拷贝.这个拷贝的精确含义取决于该对象的类.一般含义是,对于任何对象x,表达式x.clone ...

  2. Effective Java 之-----谨慎的覆盖clone方法

    1.概述 如果clone方法返回一个由构造器创建的对象,它就得到有错误的类.因此,如果覆盖了非final类中的clone方法,则应该返回一个通过调用super.clone得到的对象.如果类的所有超类都 ...

  3. 第十一条:谨慎的覆盖clone()方法

    一个类要想实现克隆,需要实现Cloneable接口,表明这个类的对象具有克隆的功能. Cloneable接口是一个mixin接口,它里面并没有任何的抽象方法,类似的接口有Serializable接口, ...

  4. Java - 谨慎覆盖clone

    覆盖clone时需要实现Cloneable接口,Cloneable并没有定义任何方法. 那Cloneable的意义是什么? 如果一个类实现了Clonable,Object的clone方法就可以返回该对 ...

  5. Effective Java 第三版——13. 谨慎地重写 clone 方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. Effective Java —— 谨慎覆盖clone

    本文参考 本篇文章参考自<Effective Java>第三版第十三条"Always override toString",在<阿里巴巴Java开发手册>中 ...

  7. item 11: 比起private undefined function优先使用deleted function

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果你为其他开发者提供代码,并且你想阻止他们调用一个特定的函数,你 ...

  8. XE3随笔11:Merge、Clone、ForcePath

    unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, For ...

  9. 读书笔记 effective c++ Item 11 在operator=中处理自我赋值

    1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...

随机推荐

  1. Java常用类之String

    String 类: 1. java.lang.String 类代表不可变的字符序列:  2. “XXX” 为该类的一个对象: 3. String 类的常用构造方法: ① String(String o ...

  2. epoll&ext4文件系统

    1.第一个终端运行nesttest,nesttest首先fork一个子进程,然后父进程退出,子进程首先打开一个txt普通文件对应fd为3,然后创建一个epfd,对应fd为4 lybxin@Inspir ...

  3. SQL SERVER技术内幕之6 集合查询

    1.定义 集合运算会对两个输入查询的结果集进行逐行比较,根据比较结果和所使用的集合运算来确定某一行是否应该包含在集合运算的结果中.因为集合运算是针对集合之间进行的计算,所以集合运算涉及的两个查询不能包 ...

  4. getGeneratedKeys自动获取主键的方法

    public class Demo { public static void main(String[] args) { try { String sql="insert into pers ...

  5. java 基础--数组--004

    1,数组定义格式 String[] aa; String aa[];2,二位数组的定义格式1 String aa[][] = new String[m][n]; String[] aa[] = new ...

  6. 在windows搭建react

    1.安装必须的软件 1.Python 2    注意勾选 Add python.exe to Path,选项,这样就可以在安装完成后,不用手动去添加环境变量    安装完,打开cmd.exe,输入py ...

  7. 限制玻尔兹曼机(Restricted Boltzmann Machine)RBM

    假设有一个二部图,每一层的节点之间没有连接,一层是可视层,即输入数据是(v),一层是隐藏层(h),如果假设所有的节点都是随机二值变量节点(只能取0或者1值)同时假设全概率分布满足Boltzmann 分 ...

  8. 【bzoj3297】[USACO2011 Open]forgot STL+dp

    题目描述 发生了这么多,贝茜已经忘记了她cowtube密码.然而,她记得一些有用的信息. 首先,她记得她的密码(记为变量P)长度为L(1 <= L<=1,000)字符串,并可以被分成 一个 ...

  9. Java异常捕捉

    相信你在处理异常的时候不是每次都把它 throws 掉就完事了,很多时候异常是需要我们自己来 catch 并针对所抛出的 Exception 做一些后续的处理工作. 直接上代码,先贴下面测试需要调用的 ...

  10. POJ2135:Farm Tour——题解

    http://poj.org/problem?id=2135 题目大意: 从1到n再回来,每条边只能走一次,问最短路. —————————————————— 如果不告诉我是费用流打死不会想这个…… 我 ...