Effective Java 11 Override clone judiciously

摘要:
原则如果您在final类中覆盖了clone方法,则应返回通过调用super.cloneInpractice获得的对象,该类实现了Cloneable,以提供正确的公共克隆功能

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》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WPF布局控件与子控件的HorizontalAlignment/VerticalAlignment属性之间的关系Elasticsearch 建立ik中文分词器和自定义分词下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

CorelDRAW 编写和运行宏指令

在开发和运行CorelDRAW宏之前,必须安装VBA组件。在CoerlDRAW11和12中安装CorelDRAWVBAVBA是典型安装的一部分。2如果安装开始,请单击安装CorelDRAW12 Graphics Suite。CorelDRAWVBA工具栏CorelDRaw工具栏提供了几个快速的VBA函数和对VB编辑器的访问。但是,您可以通过在CorelDRA...

Json对象转Ts类

其次,Json是一种轻量级的数据交换格式。在前端和后端之间的数据交互过程中,后端接口返回Json格式的数据,前端需要使用相应的Ts类对象来接收它。此时,如果后端提供样本数据或现有接口返回的Json格式数据,是否有方法帮助我们从Json格式数据生成Ts类?介绍了三个主要功能。1.查看Json对应的Ts类,将要格式化的Json字符串复制粘贴到中间编辑区域。单击右...

流控制、FlowControl

作用就是防止网络拥堵时导致的“丢包”问题,大致的工作原理就是当链路两端的设备有一端忙不过来了,他会给另外一端的设备发一个暂停发包的命令,通过这种方式来缓解压力,解决丢包问题。看上去流控制应该是个非常好的防止丢包的方法,但是为什么我们还要在无盘上关闭他呢?...

uni-app 安卓和IOS更新方案

热更新资源,即重新安装应用程序,并更新js等前端代码。Android平台更新方案,详见上一篇文章https://www.cnblogs.com/tiandi/p/15331522.html二、2015年,IOS平台苹果发布了一项规定,禁止用户在应用程序中被提示进行版本更新。无法直接更新通用iOSAppstore的安装包。应用程序启动后,检查是否有新版本,该版...

异步复位和同步释放电路的详细解释

我发现互联网上很多关于异步重置和同步释放的解释都是错误的。以下解释非常清楚。转移自:http://www.xue5.com/Developer/Software/665219.html如图所示,第一个盒子包含异步复位和同步释放电路。第一级D触发器的输入是VCC,第二级触发器的输出是可以异步复位和同步释放的复位信号。所谓异步复位和同步释放是指复位信号是异步和有...

Web.config

在本文中,我们将解决以下问题:什么是网络。配置文件?网络的影响是什么。部署时的配置?一般来说,网络。config文件包含运行ASP所需的所有配置信息。NET应用程序。当然,配置文件并不包含所有配置。服务器范围的配置文件还包含applicationHost.config。...