Effective Java 11 Override clone judiciously
Principles
- If you override the clone method in a nonfinal class, you should return an object obtained by invoking super.clone
- In practice, a class that implements Cloneable is expected to provide a properly
functioning public clone method.
- Never make the client do anything the library can do for the client.
- 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
- Like a constructor, a clonemethod should not invoke any nonfinal methods on the clone under construction (Item 17).
- 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.
- To make a thread-safe class implement Cloneable you must ensure its clone method be synchronized just like other methods.
- Class which implement Cloneable should override clone with public method return itself.
- First call super.clone.
- Fix any fields that is not primitive or immutable type object.
- Call the field's clone method recursively.
- 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.
- 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.
- Public Yum(Yum yum);
- Public static Yum newInstance(Yum yum);
Effective Java 11 Override clone judiciously的更多相关文章
- Effective Java —— 谨慎覆盖clone
本文参考 本篇文章参考自<Effective Java>第三版第十三条"Always override toString",在<阿里巴巴Java开发手册>中 ...
- Effective Java 41 Use overloading judiciously
The choice of which overloading to invoke is made at compile time. // Broken! - What does this progr ...
- Effective Java 42 Use varargs judiciously
Implementation theory The varargs facility works by first creating an array whose size is the number ...
- Effective Java 74 Implement Serializable judiciously
Disadvantage of Serializable A major cost of implementing Serializable is that it decreases the flex ...
- 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 ...
- 《Effective Java》读书笔记 - 3.对于所有对象都通用的方法
Chapter 3 Methods Common to All Objects Item 8: Obey the general contract when overriding equals 以下几 ...
- Effective Java 目录
<Effective Java>目录摘抄. 我知道这看起来很糟糕.当下,自己缺少实际操作,只能暂时摘抄下目录.随着,实践的增多,慢慢填充更多的示例. Chapter 2 Creating ...
- 【Effective Java】阅读
Java写了很多年,很惭愧,直到最近才读了这本经典之作<Effective Java>,按自己的理解总结下,有些可能还不够深刻 一.Creating and Destroying Obje ...
- Effective Java 第三版——13. 谨慎地重写 clone 方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- [python]初探socket
1.什么是socket? Socket中文译作:套接字,但是大家一般约定俗称的都用:socket.我想在解释socket是什么之前,先说它是用来干嘛的:socket是来建立'通信'的基础,建立连接,传 ...
- Angular系列----AngularJS入门教程04:迭代器过滤(转载)
我们在上一步做了很多基础性的训练,所以现在我们可以来做一些简单的事情喽.我们要加入全文检索功能(没错,这个真的非常简单!).同时,我们也会写一个端到端测试,因为一个好的端到端测试可以帮上很大忙.它监视 ...
- IOS开发UI基础之Plis文件-字典转模型
什么是plist文件? 在开发中直接将数据写在代码里面 不是一种合理的做法 如果数据经常改变 就需要经常翻开对应的代码进行修改 造成代码扩展性低 因此,可以考虑将经常变的数据放在⽂文件中进⾏行存储,程 ...
- 暴力 + 贪心 --- Codeforces 558C : Amr and Chemistry
C. Amr and Chemistry Problem's Link: http://codeforces.com/problemset/problem/558/C Mean: 给出n个数,让你通过 ...
- 译:什么是ViewData的, ViewBag和TempData? - MVC为当前和后续请求之间传递数据的三种方法
译文出处:http://www.codeproject.com/Articles/476967/WhatplusisplusViewData-cplusViewBagplusandplusTem AS ...
- js获取url参数的两种方法
js获取参数,在以前我都是用正在去拆分,然后获取,这种方式感觉是最简单的 方式1: function QueryString(item) { var sValue=location.search.ma ...
- 用C#开发的双色球走势图(二)
昨晚由于时间的原因只写了一部分内容,今天将这一部分内容补充完毕,多谢各位园友的支持. 这是用C#开发的双色球走势图(一)新的园友可以看昨晚写的内容,以免脱节.首先回复园友的评论,有说好的有说不好的,本 ...
- Redis持久化-数据丢失及解决
Redis的数据回写机制 Redis的数据回写机制分同步和异步两种, 同步回写即SAVE命令,主进程直接向磁盘回写数据.在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的. 异步回写即BGSA ...
- Python记录-Pip安装
1.第一步 下载py文件:https://bootstrap.pypa.io/ez_setup.py #!/usr/bin/env python """ Setuptoo ...
- LeetCode127:Word Ladder II
题目: Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...