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=

随便看看

PowerDesigner 15 使用技巧

1.检索PowerDesigner的调色板工具栏工具&gt;自定义大小工具栏&gt;调色板检查2。在表格工具中批量修改文本格式&gt;显示首选项&gt;选择符号中的所有项目&gt;...

利用adb实时查看应用日志

出现乱码解决办法:就是通过chcp命令改变代码页,UTF-8的代码页为65001,输入命令:,执行该操作后,代码页就被变成UTF-8了。...

IPI 通信(SMP)【转】

在MIPS架构下的IPI通信被关闭和中断后,IPIMIPS接口结构平台也将被发送_ smp_Ops{void;void;…}IPI通信是多个处理器之间的通信。send_ ipi_Single:一对一聊天send_ ipi_Mask:Mask posting,Mask表示Mask posting/*Octeon Tellanothercore of Lushi...

oracle的序列号(sequence)

Oracle的自动递增列应使用序列号。在初始化阶段,需要手动创建序列,然后在插入序列时手动读取分配给相关字段(如ID)的序列的nextval。这很麻烦。但是,这对于SQL Server来说不是问题,可以获得。oracle的序列号也有缓存。默认情况下,一次生成20个。如果没有用完,它们可能会丢失,这可能会导致ID不一致。此外,有时这可能会引起误解。例如,我有一...

adb

ADB(AndroidDebugBridge)ANR(ApplicationNoResponding)ADB实际上是Android调试桥AndroidDebugBridge的缩写。adb是C/S体系结构的命令行工具。这里我们介绍一些常用的命令:adbdevices,获取设备列表和设备状态[xuxu:~]$adbdevicesList-devicesattac...

传奇服务端各文件用途说明

传奇外传服务端├数据库服务器│├联系│├美国联邦储备银行│├日志│├! ID列表。txt(付款帐户列表,在Setup.exe中ServiceMode=TRUE时有效)!服务器信息.txt│├DBServer.exe│└DBSrc.ini├登录门│├登录网关.exe│└配置ini├登录服务器│├Chr日志│├ConLog公司│├计数日志│├国际数据库││├ID...