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=

随便看看

14款优秀的JavaScript调试工具大盘点

官方网站:http://www.jshint.com/4.Grunt Grunt是一个基于任务的命令行构建工具,适用于JavaScript项目。Venkman旨在为Mozilla提供一个基于浏览器的强大JavaScript调试环境。官方网站:http://www.my-debugbar.com/wiki/CompanionJS/HomePage10.Simp...

java.net.URISyntaxException的解决办法

直接采用Stringurl=“http:count=1”;HttpGethttpget=新的HttpGet(url);HttpResponseresponse=client.execute(httpget);例如,“|”&amp;因此,不能直接使用String而不是URI来访问。然后我们可以使用URL生成URI的方法来解决这个问题。代码如下:URLu...

zlog 使用手册

Zlog是一个纯C日志函数库,具有高可靠性、高性能、线程安全性、灵活性和清晰的概念。Syslog是一个系统级的轮子,但它的速度慢,功能单调。Zlog比log4c更高效、更实用、更安全,它是用c编写的。Zlog使用了C99兼容的vsnprintf。...

windows下mstsc 远程Ubuntu 教程

为远程桌面控制设置Ubuntu 16.04的缺点是重新启动系统需要使用监视器登录系统。首先,我们将Ubuntu远程控制设置为允许远程连接,进入系统-˃首选项-˃桌面共享,或直接搜索桌面共享。如图所示,选中此项,然后选中安全项,并设置远程密码。...

如何控制el-image预览图片的大小

Src=“scope.row.carlouseUrl”:1。从“element-ui/packages/image/src/image-viewer”2导入图像查看器importerImageViewer。寄存器组件:3。使用组件&lt;El table columnlabel=“旋转图表”width=“220px”&gt;...

数据可视化之powerBI技巧(十四)采悟:PowerBI中自制中文单位万和亿

最令人不快的事情之一是数据单元的设置。现在让我们看看如何通过设置测量值来切换单位。需要动态选择1万元和1亿元的单位进行显示。首先,手动创建单位表,然后使用单位表中的[unit]字段生成切片器。下一步是建立销售衡量标准。销售额=总和('订单'[销售额])为了按过滤单位显示销售额,SELECTEDVALUE函数可以根据切片器选择动态更改分母。如果切片器未进行任何...