Principles

  1. If you override the clone method in a nonfinal class, you should return an object obtained by invoking super.clone
  2. In practice, a class that implements Cloneable is expected to provide a properly

    functioning public clone method.

  3. Never make the client do anything the library can do for the client.
  4. The clone architecture is incompatible with normal use of final fields referring to mutable objects

Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.

The general intent is that, for any object x, the expression

x.clone() != x will be true,

x.clone().getClass() == x.getClass() will be true,

but these are not absolute requirements. While it is typically the case that

x.clone().equals(x) will be true,

this is not an absolute requirement. Copying an object will typically entail creating a new instance of its class, but it may require copying of internal data structures as well. No constructors are called.

The return type of the method is subclass instead of the super class which means this is applied with covariant which is introduced from JRE 1.5. As the code shown below:

@Override public PhoneNumber clone() {

try {

return (PhoneNumber) super.clone();

} catch(CloneNotSupportedException e) {

throw new AssertionError(); // Can't happen

}

}

import java.util.Arrays;

import java.util.EmptyStackException;

public class Stack implements Cloneable {

private Object[] elements;

private int size = 0;

private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Stack() {

this.elements = new Object[DEFAULT_INITIAL_CAPACITY];

}

public void push(Object e) {

ensureCapacity();

elements[size++] = e;

}

public Object pop() {

if (size == 0)

throw new EmptyStackException();

Object result = elements[--size];

elements[size] = null; // Eliminate obsolete reference

return result;

}

// Ensure space for at least one more element.

private void ensureCapacity() {

if (elements.length == size)

elements = Arrays.copyOf(elements, 2 * size + 1);

}

@Override

protected Object clone() throws CloneNotSupportedException {

try {

Stack result = (Stack) super.clone();

// Do recursive clone with a class.

result.elements = elements.clone();

return result;

} catch (CloneNotSupportedException e) {

throw new AssertionError();

}

}

}

Implement clone with recursive clone method.

public class Hashtable implements Cloneable {

private Entry[] buckets = new Entry[3];

private static class Entry {

final Object key;

Object value;

Entry next;

Entry(Object key, Object value, Entry next) {

this.key = key;

this.value = value;

this.next = next;

}

// Recursively copy the linked list headed by this Entry

Entry deepCopy() {

return new Entry(key, value, next == null ? null : next.deepCopy());

}

@Override

public String toString() {

return String.format("[key: %d, value: %s, next: %s]", key, value,

next);

}

}

public static void main(String[] args) {

Hashtable ht = new Hashtable();

Entry previous = null;

for (int i = 0; i < 3; i++) {

Entry e = new Entry(i, "v" + i, previous);

ht.buckets[i] = e;

}

Hashtable newHt = ht.clone();

newHt.buckets[newHt.buckets.length - 1] = new Entry(

newHt.buckets[newHt.buckets.length - 1].key,

newHt.buckets[newHt.buckets.length - 1].value

+ String.valueOf(1),

newHt.buckets[newHt.buckets.length - 1].next);

System.out.println("newHt");

for (int i = 0; i < newHt.buckets.length; i++) {

System.out.println(newHt.buckets[i]);

}

System.out.println("ht");

for (int i = 0; i < ht.buckets.length; i++) {

System.out.println(ht.buckets[i]);

}

}

@Override

public Hashtable clone() {

try {

Hashtable result = (Hashtable) super.clone();

result.buckets = new Entry[buckets.length];

for (int i = 0; i < buckets.length; i++)

if (buckets[i] != null)

result.buckets[i] = buckets[i].deepCopy();

return result;

} catch (CloneNotSupportedException e) {

throw new AssertionError();

}

}

}

To prevent a stack overflow caused by the lengthy stack frame for each element in the list from happening. We can implement the code like this below:

// Iteratively copy the linked list headed by this Entry

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;

}

Summary

  1. Like a constructor, a clonemethod should not invoke any nonfinal methods on the clone under construction (Item 17).
  2. Object's clone method is declared to throw CloneNotSupportedException, but overriding clone methods can omit this declaration. But if the subclass overrides its superclass's clone method it should be declared as proteteced and throw CloneNotSupportedException and the class should not implment Cloneable.
  3. To make a thread-safe class implement Cloneable you must ensure its clone method be synchronized just like other methods.
  4. Class which implement Cloneable should override clone with public method return itself.
    1. First call super.clone.
    2. Fix any fields that is not primitive or immutable type object.
      1. Call the field's clone method recursively.
      2. Handle the exception case that if the object represent a unique ID or serial number or creating time even if they are primitive type or a reference to immutable object.
  5. If it's not appropriate way to provide an alternative means of object coping or simply not providing the capability of cloneable(such as immutable class) then just provide a copy constructor or copy factory.
    1. Public Yum(Yum yum);
    2. Public static Yum newInstance(Yum yum);

Effective Java 11 Override clone judiciously的更多相关文章

  1. Effective Java —— 谨慎覆盖clone

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

  2. Effective Java 41 Use overloading judiciously

    The choice of which overloading to invoke is made at compile time. // Broken! - What does this progr ...

  3. Effective Java 42 Use varargs judiciously

    Implementation theory The varargs facility works by first creating an array whose size is the number ...

  4. Effective Java 74 Implement Serializable judiciously

    Disadvantage of Serializable A major cost of implementing Serializable is that it decreases the flex ...

  5. Effective Java Index

    Hi guys, I am happy to tell you that I am moving to the open source world. And Java is the 1st langu ...

  6. 《Effective Java》读书笔记 - 3.对于所有对象都通用的方法

    Chapter 3 Methods Common to All Objects Item 8: Obey the general contract when overriding equals 以下几 ...

  7. Effective Java 目录

    <Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...

  8. 【Effective Java】阅读

    Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...

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

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

随机推荐

  1. Android开发切换host应用

    由于在工作过程中常需要切换手机的host来测试不同服务器上的接口,所以想到需要这么个软件. SwitchHost在PC上是一款很好用的修改Host的软件,手机上也需要这么一款App(当然手机需要已经R ...

  2. CentOS6.5菜鸟之旅:安装VirtualBox4.3

    一.下载VirtualBox的RHEL软件库配置文件 cd /etc/yum.repos.d wget http://download.virtualbox.org/virtualbox/rpm/rh ...

  3. EF错误记录

    纯属个人记录错误使用: 1.EntityType“area”未定义键.请为该 EntityType 定义键. 产生原因: 1.命名空间引用错误,可能命名重复导致引用错误 2.实体类无法识别主键或者未设 ...

  4. OpenProcess打开进程返回错误的问题

    问题描述 项目中需要做一个小功能:能够查看系统中当前正在运行的进程的内存信息,如内存块类型.分配状态.访问权限等.如下图所示: 需要的信息和上图相差无几.说起来也不算太难,毕竟现成的API已经提供了. ...

  5. 【JS复习笔记】04 数组

    JS里的数组其实并不是一个数组,它其实是一个对象,a[1]这种调用方式其实就是一个字面量为1的属性. 因为这东西实际上是一个对象,所以你就可以理解下面这种声明了吧! var arrName=['我可以 ...

  6. 重新想象 Windows 8.1 Store Apps (79) - 控件增强: MediaElement, Frame

    [源码下载] 重新想象 Windows 8.1 Store Apps (79) - 控件增强: MediaElement, Frame 作者:webabcd 介绍重新想象 Windows 8.1 St ...

  7. csharp: Socket

    https://github.com/joeandaverde/socket.io-csharp-client http://websocket4net.codeplex.com/ http://ww ...

  8. Qt 框架 开发HTTP 服务器 开发记录

    最近需求需要开发一款 HTTP ,然后由于先前接触过Qt,就直接用Qt写HTTP服务器了,也是为了当作练手,要不然是直接上HTTP框架的. 后端用C++ Qt框架 前端为了练手 当然是纯生的 js h ...

  9. Servlet-Jsp

    Jsp实际就是Servlet. 我们访问Http://localhost:8080/Web/index.jsp的流程: 1 [jsp文件名].jsp转义为[jsp文件名_jsp].java,文件存储在 ...

  10. 批处理清除VisualStudio解决方案文件夹

         有很多次我们需要手工来删除bin, obj这样的文件夹.这些文件夹是由Visual Studio编译项目时生成的,其中包括了当前项目的程序集.一个解决方案会包含好多个项目了,那么就有很多这样 ...