Item 11 谨慎地覆盖Clone
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的更多相关文章
- 第11条:谨慎地覆盖clone
Clone提供一种语言之外的机制:无需调用构造器就可以创建对象. 它的通用约定非常弱: 创建和返回该对象的一个拷贝.这个拷贝的精确含义取决于该对象的类.一般含义是,对于任何对象x,表达式x.clone ...
- Effective Java 之-----谨慎的覆盖clone方法
1.概述 如果clone方法返回一个由构造器创建的对象,它就得到有错误的类.因此,如果覆盖了非final类中的clone方法,则应该返回一个通过调用super.clone得到的对象.如果类的所有超类都 ...
- 第十一条:谨慎的覆盖clone()方法
一个类要想实现克隆,需要实现Cloneable接口,表明这个类的对象具有克隆的功能. Cloneable接口是一个mixin接口,它里面并没有任何的抽象方法,类似的接口有Serializable接口, ...
- Java - 谨慎覆盖clone
覆盖clone时需要实现Cloneable接口,Cloneable并没有定义任何方法. 那Cloneable的意义是什么? 如果一个类实现了Clonable,Object的clone方法就可以返回该对 ...
- Effective Java 第三版——13. 谨慎地重写 clone 方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java —— 谨慎覆盖clone
本文参考 本篇文章参考自<Effective Java>第三版第十三条"Always override toString",在<阿里巴巴Java开发手册>中 ...
- item 11: 比起private undefined function优先使用deleted function
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 如果你为其他开发者提供代码,并且你想阻止他们调用一个特定的函数,你 ...
- XE3随笔11:Merge、Clone、ForcePath
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, For ...
- 读书笔记 effective c++ Item 11 在operator=中处理自我赋值
1.自我赋值是如何发生的 当一个对象委派给自己的时候,自我赋值就会发生: class Widget { ... }; Widget w; ... w = w; // assignment to sel ...
随机推荐
- 软件工程课堂作业(十一)——NABC分析
一.团队开发项目:基于Android的重力感应的解锁APP 二.项目特点:区别于一般解锁软件用开机按钮开锁解锁,我们的重力解锁软件根据动作实现解锁,减少了开机按钮的使用频率,提高寿命. 三.NABC分 ...
- khan academy js
Documentation Quick Jump: Shapes, Complex Shapes, Colors, Text, Transforms, Environment, Mouse, Keyb ...
- JS DOM视频相关的知识
1.实现点击a标签改变图片时,如果a的href属性有一个目标网址,但是点击又必须跳转到另外一张图,往往会最后跳转到目标网址,可以在onclick事件函数中加入ruturn false,阻止跳转到页面. ...
- oracle 9i 图文安装教程 oracle 9i 安装
我的安装文件是ISO镜像文件,使用Virtual DAEMON Manager v 4.10打开: ora9i-1.iso ora9i-2.iso ora9i-3.iso 首先必须把上面三个镜像文件都 ...
- c运行时库,c标准库,Windows系统api的关系
原文地址:http://blog.csdn.net/seastars_sh/article/details/8233324 C运行库和C标准库的关系 C标准库,顾名思义既然是标准,就是由标准组织制定的 ...
- 移动端body跟着模态框一起滑动问题
遇到了一个问题,是点击链接出现弹框,弹框里面的内容是可以滑动的,结果我滑动的时候发现下面的body也跟着一起滑动,先看一下代码. 弹框的 HTML: <div class="mask& ...
- P1120 小木棍 [数据加强版](poj 1011)
题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度. 给出每段小木棍的长度,编 ...
- JavaScript 面向对象开发知识基础总结
JavaScript 面向对象开发知识基础总结 最近看了两本书,书中有些内容对自己还是很新的,有些内容是之前自己理解不够深的,所以拿出来总结一下,这两本书的名字如下: JavaScript 面向对象精 ...
- 学习web安全之--初识安全
随笔:随着互联网行业的飞速发展,互联网行业可谓日新月异,然而在繁华的背后,大多的互联网公司对于网络安全还是处于无重视,不作为的阶段,而作为一个程序员,如果也对信息安全视而不见的话,那将是这个公司的噩梦 ...
- node.js 与java 的主要的区别是什么
node.js 与java都是服务器语言,但是两者存在很大区别:(1)Node.js比Java更快 :node.js开发快,运行的效率也算比较高,但是如果项目大了就容易乱,而且javascript不是 ...