1、概述

  如果clone方法返回一个由构造器创建的对象,它就得到有错误的类。因此,如果覆盖了非final类中的clone方法,则应该返回一个通过调用super.clone得到的对象。
如果类的所有超类都遵循这条规则,那么调用super.clone最终会调用Object的clone方法,从而创建出正确的实例。这种机制类似于自动的构造器调用链,只不过它不是强制要求的。

2、示例

需求: 为HashTable编写一个clone方法,它内部数据包含一个HashTable数组,每个HashTable都指向键值对列表的第一个项,如果table是空的,返回null。

代码实现如下:

public class HashTable implements Cloneable {
private Entry[] buckets; private static class Entry{
Object key;
Object value;
Entry next; Entry(Object key, Object value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
}
//......
} //递归clone这个HashTable数组,如下:
public HashTable clone(){
HashTable result = new HashTable();
try {
result = (HashTable) super.clone();
result.buckets = buckets.clone();
return result;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return result;
}

  虽然被clone对象有它自己的HashTable数组,但这个数组引用的链表与原始对象是一样的,从而很容易引起clone对象和原始对象中的不确定的行为,为了修正这个问题,必须单独的拷贝并组成每个桶的链表,实现如下:

public class HashTable1 implements Cloneable {
private Entry[] buckets; private static class Entry{
Object key;
Object value;
Entry next; Entry(Object key, Object value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
} Entry deepCopy(){
Entry result = new Entry(key,value,next);
for(Entry p=result;p.next !=null; p=p.next){
p.next=new Entry(p.next.key,p.next.value,p.next.next);
}
return result;
}
}
//...... public HashTable1 clone(){
HashTable1 result = new HashTable1();
try {
result = (HashTable1) super.clone();
result.buckets = new Entry[buckets.length];
for(int i=0;i<buckets.length;i++){
result.buckets[i] = buckets[i].deepCopy();
}
return result;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return result;
}
}

  步骤:先调用super.clone方法,然后把结果对象中的所有域都设置称他们的空白状态,然后调用高层的方法来重新产生对象的状态。

3、总结

  简而言之,所有实现了Cloneable接口的类都应该用一个公有的方法覆盖clone,此方法首先调用super.clone,然后修正任何需要修正的域。一般情况下,这意味着要拷贝任何包含内部“深层结构”的可变对象,并用指向新对象的引用代替原来指向这些对象的引用。

Effective Java 之-----谨慎的覆盖clone方法的更多相关文章

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

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

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

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

  3. Item 11 谨慎地覆盖Clone

    1.进行浅拷贝时,只是复制原始数据类型的值,则可以通过覆盖Clone方法来达到.另外,在进行浅拷贝的时候,还要注意,成员对象中不应该要有引用类型,如果有引用类型,那么,进行了浅拷贝之后,两个对象将会共 ...

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

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

  5. Effective java笔记(六),方法

    38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...

  6. 《Effective Java》读书笔记六(方法)

    No38 检查参数的有效性 对于公有的方法,要用Javadoc的@throws标签(tag)在文档中说明违反参数值时会抛出的异常.这样的异常通常为IllegalArgumentException.In ...

  7. java开发——Cloneable接口、clone()方法和深浅拷贝

    1.实现Cloneable接口表明该类的对象是允许克隆的. 2.允许克隆的意思是:可以调用clone()方法. 3.深拷贝还是浅拷贝,取决于如何重写Object的clone()方法. 4.原对象和克隆 ...

  8. 《Effective Java 2nd》第7章 方法

    目录 第38条 检查参数的有效性 第39条 必要时进行保护性拷贝 第40条 谨慎设计方法签名 第41条 慎用重载 第42条 慎用可变参数 第43条 返回零长度的数组或集合,而不是null 第44条 为 ...

  9. [Effective Java 读书笔记] 第7章 方法

    第39条 必要时进行保护性拷贝 对于可变类,如果作为参数传入到自己的类里,并作为自己类的数据使用存储时,需要进行保护性拷贝,比如Date是可变的,如果传入一个Date类,最好做一个保护性拷贝,以免在调 ...

随机推荐

  1. 使用Android-PullToRefresh实现下拉刷新功能

    源代码:https://github.com/chrisbanes/Android-PullToRefresh 一. 导入类库 将Library文件夹作为Android项目Import到Eclipse ...

  2. 利用cmd制作一句话图片马

    先cd进在图片和一句话木马里面的文件夹 假设选择我的图片是:1.jpg 一句话是:2.php 命令:copy 1.jpg/a+2.php/b 生成的图片马

  3. 【Java学习笔记之十】Java中循环语句foreach使用总结及foreach写法失效的问题

    foreach语句使用总结 增强for(part1:part2){part3}; part2中是一个数组对象,或者是带有泛性的集合. part1定义了一个局部变量,这个局部变量的类型与part2中的对 ...

  4. Codeforces 839E Mother of Dragons【__builtin_popcount()的使用】

    E. Mother of Dragons time limit per test:2 seconds memory limit per test:256 megabytes input:standar ...

  5. BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, ...

  6. ES5.0集群搭建

    最近在网上看到很多ES集群的搭建方法,本人在这人使用Elasticsearch5.0.1版本,介绍如何搭建es集群并安装head插件和其他插件安装方法. 一.搭建环境(2台Centos7系统服务器) ...

  7. python笔记一(正则表达式)

    #!/usr/bin/env python # -*- coding: utf-8 -*- # 1 如果直接给出字符,则表示精确匹配 # 2 \d 表示数字, \w 表示字母或数字, . 可以匹配任意 ...

  8. Entity Framework Core 懒加载

    众所周知在EF 6 及以前的版本中,是支持懒加载(Lazy Loading)的,可惜在EF Core 并不支持,必须使用Include方法来支持导航属性的数据加载.不过现在EF Core的开发团队打算 ...

  9. MyBatis工作原理

    Mybatis工作原理: 我们的应用程序通过mybatis提供的api,增删改查方法来访问数据库,api底层调用了jdbc ,只不过mybatis对jdbc的封装是不完全封装,里面的sql语句需要我们 ...

  10. 将TinyXml快速入门的接口面向对象化(转载)

    作者:朱金灿 来源:http://www.cnblogs.com/clever101 在TinyXml快速入门的系列文章中(详情见本博客),我只是将tinyxml类库解析xml文件的类封装为API接口 ...