目前各通讯运营商的月吉林市五月花最低消费费低到多少?

2011年10月 Java大版内专家分月排行榜第三
2011年10月 Java大版内专家分月排行榜第三
2011年10月 Java大版内专家分月排行榜第三
2011年10月 Java大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。Effective Java - 谨慎覆盖clone_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Effective Java - 谨慎覆盖clone
来源:Linux社区&
作者:Kavlez
覆盖clone时需要实现Cloneable接口,Cloneable并没有定义任何方法。那Cloneable的意义是什么?如果一个类实现了Clonable,Object的clone方法就可以返回该对象的逐域拷贝,否则会抛出CloneNotSupportedException。
通常,实现接口是为了表明类的行为。而Cloneable接口改变了超类中protected方法的行为。这是种非典型用法,不值得仿效。
好了,既然覆盖了clone方法,我们需要遵守一些约定:
x.clone() !=
x.clone().getClass() = x.getClass();
x.clone().equals(x);
另外,我们必须保证clone结果不能影响原始对象的同时保证clone方法的约定。
比如下面这种情况,没有覆盖clone方法,直接得到super.clone()的结果:
import java.util.A
public class Stack implements Cloneable {
private Object[]
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++] =
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
public boolean isEmpty() {
return size == 0;
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
结果可想而知,clone结果的elements和原始对象的elements引用同一个数组。
既然如此,覆盖clone方法,并保证不会伤害到原始对象:
public Stack clone() {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
虽然把elements单独拿出来clone了一遍,但这种做法的前提是elements不是final。其实再正常不过,clone无法和引用可变对象的不可变field兼容。
如果数组的元素是引用类型,当某个元素发生改变时仍然会出现问题。此处以Hashtable为例,Hashtable中的元素用其内部类Entry。
private static class Entry&K,V& implements Map.Entry&K,V& {
Entry&K,V&
protected Entry(int hash, K key, V value, Entry&K,V& next) {
this.hash =
this.key =
this.value = value;
this.next =
如果像Stack例子中那样直接对elements进行clone,某个Entry发生变化时clone出来的Hashtable也随之发生变化。
于是Hashtable中如此覆盖clone:
* Creates a shallow copy of this hashtable. All the structure of the
* hashtable itself is copied, but the keys and values are not cloned.
* This is a relatively expensive operation.
a clone of the hashtable
public synchronized Object clone() {
Hashtable&K,V& t = (Hashtable&K,V&) super.clone();
t.table = new Entry[table.length];
for (int i = table. i-- & 0 ; ) {
t.table[i] = (table[i] != null)
? (Entry&K,V&) table[i].clone() : null;
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
} catch (CloneNotSupportedException e) {
throw new InternalError();
鉴于clone会导致诸多问题,有两点建议:
不要扩展Cloneable接口
为继承而设计的类不要实现Cloneable接口
本文永久更新链接地址:
相关资讯 & & &
& (05/01/:27)
& (01/18/:08)
& (06/23/:19)
& (01/18/:09)
& (01/18/:48)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款leizhimin 的BLOG
用户名:leizhimin
文章数:725
评论数:2719
注册日期:
阅读量:5863
阅读量:12276
阅读量:413510
阅读量:1101260
51CTO推荐博文
Java克隆(Clone)的应用
Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。
对于克隆(Clone),Java有一些限制:
1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。
2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。
3、在Java.lang.Object类中克隆方法是这么定义的:
protected Object clone()
&&&&&&&&&&&&&&& throws CloneNotSupportedException
创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。
按照惯例,返回的对象应该通过调用 super.clone 获得。
举个例子说吧,现在有一个对象比如叫foo,你需要在创建当前对象的一个副本作为存根你能怎么做?
假如你不用Clone,那么你可以先new一个对象foo1:Foo foo1=new Foo(),然后用foo给foo1对象set值,这样就得到foo的副本foo1;除此之外,别无选择。
这样说,也许有人会觉得说的过于绝对了,不过事实如此啊。
要产生一个副本,那副本要不要内存?----当然要了,那就对了!既然需要内存,(不克隆的情况下)你不new还有什么办法呢?请大家时刻铭记对象是Java运行时产生的,驻留在计算机内存中。
常见错误:
下面我澄清几个初学者容易犯迷糊的错误,同样的问题,产生foo对象的副本:
1、Foo foo1=new Foo();
&& 然后就想当然的认为副本foo1生成了!
错误原因:foo1没错是申请了内存,但是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo1、foo指向了同一内存区域。刚才new的操作制造一堆垃圾等着JVM回收。
2、Foo foo1=
错误原因:还是两个变量都指向了同一块内存。
3、有些老鸟更厉害一些:在Foo中定义一个返回自身的方法:
&&& public Foo getInstance(){
&&& 然后,Foo foo1=foo.getInstance();
错误原因:同上,主要还是没有重新开辟内存,this在对象里是什么?----就是对象自己的引用!那么getInstance()自然返回的就是对象自己,反正又是两个对象穿了一条裤子----***,哈哈。错得心服口服吧。为了节省篇幅,我在最后写个例子,留给那些对此有异议的人看。
看了这么多方法都不行,还很麻烦!干脆用克隆吧,简单明了。
废话不说了,看例子:
定义两个类CloneFooA、CloneFooB,然后写个测试类CloneDemo分别克隆这两个类的对象,然后打印测试结果到控制台。
&* Created by IntelliJ IDEA.
&* User: leizhimin
&* Time: 19:40:44
&* 简单类克隆实现
&* 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法
&* 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
&* 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
public class CloneFooA implements Cloneable {
&&& private String strA;
&&& private int intA;
&&& public CloneFooA(String strA, int intA) {
&&&&&&& this.strA = strA;
&&&&&&& this.intA = intA;
&&& public String getStrA() {
&&&&&&& return strA;
&&& public void setStrA(String strA) {
&&&&&&& this.strA = strA;
&&& public int getIntA() {
&&&&&&& return intA;
&&& public void setIntA(int intA) {
&&&&&&& this.intA = intA;
&&&& * @return 创建并返回此对象的一个副本。
&&&& * @throws CloneNotSupportedException
&&& public Object clone() throws CloneNotSupportedException {
&&&&&&& //直接调用父类的clone()方法,返回克隆副本
&&&&&&& return super.clone();
&* Created by IntelliJ IDEA.
&* User: leizhimin
&* Time: 19:59:55
&* 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆
public class CloneFooB implements Cloneable {
&&& private CloneFooA fooA;
&&& private Double douB;
&&& public CloneFooB(Double douB) {
&&&&&&& this.douB = douB;
&&& public CloneFooB(CloneFooA fooA, Double douB) {
&&&&&&& this.fooA = fooA;
&&&&&&& this.douB = douB;
&&& public CloneFooA getFooA() {
&&&&&&& return fooA;
&&& public void setFooA(CloneFooA fooA) {
&&&&&&& this.fooA = fooA;
&&& public Double getDouB() {
&&&&&&& return douB;
&&& public void setDouB(Double douB) {
&&&&&&& this.douB = douB;
&&&& * 克隆操作
&&&& * @return 自身对象的一个副本
&&&& * @throws CloneNotSupportedException
&&& public Object clone() throws CloneNotSupportedException {
&&&&&&& //先调用父类的克隆方法进行克隆操作
&&&&&&& CloneFooB cloneFooB = (CloneFooB) super.clone();
&&&&&&& //对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常
&&&&&&& if (this.fooA != null)
&&&&&&&&&&& cloneFooB.fooA = (CloneFooA) this.fooA.clone();
&&&&&&& return cloneFooB;
/**&* Created by IntelliJ IDEA.&* User: leizhimin&* Date: &* Time: 19:52:01&* 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果.&*/public class CloneDemo {
&&& public static void main(String args[]) throws CloneNotSupportedException {
&&&&&&& //CloneFooA克隆前
&&&&&&& CloneFooA fooA1 = new CloneFooA("FooA", 11);
&&&&&&& System.out.println("CloneFooA的对象克隆前对象fooA1值为: " + fooA1.getStrA() + "," + fooA1.getIntA());
&&&&&&& //CloneFooA克隆后
&&&&&&& CloneFooA fooA2 = (CloneFooA) fooA1.clone();
&&&&&&& System.out.println("CloneFooA的对象克隆后对象fooA2值为: " + fooA2.getStrA() + "," + fooA2.getIntA());
&&&&&&& //比较fooA1和fooA2内存地址
&&&&&&& if (fooA1 == fooA2) System.out.println("比较fooA1和fooA2内存地址:相等!");
&&&&&&& else System.out.println("比较fooA1和fooA2内存地址:不相等!");
&&&&&&& System.out.println("-------------------------");
&&&&&&& //CloneFooB克隆前
&&&&&&& CloneFooB fooB1 = new CloneFooB(fooA1, new Double("33"));
&&&&&&& System.out.println("CloneFooB的对象克隆前对象fooB1值为: " + fooB1.getFooA().getStrA() + "," + fooB1.getFooA().getIntA() + " | " + fooB1.getDouB());
&&&&&&& //CloneFooB克隆后
&&&&&&& CloneFooB fooB2 = (CloneFooB) fooB1.clone();
&&&&&&& System.out.println("CloneFooB的对象克隆前对象fooB2值为: " + fooB2.getFooA().getStrA() + "," + fooB2.getFooA().getIntA() + " | " + fooB2.getDouB());
&&&&&&& if (fooA1 == fooA2) System.out.println("比较fooB1和fooB2内存地址:相等!");
&&&&&&& else System.out.println("比较fooB1和fooB2内存地址:不相等!");
运行结果:
CloneFooA的对象克隆前对象fooA1值为: FooA,11CloneFooA的对象克隆后对象fooA2值为: FooA,11比较fooA1和fooA2内存地址:不相等!-------------------------CloneFooB的对象克隆前对象fooB1值为: FooA,11 | 33.0CloneFooB的对象克隆前对象fooB2值为: FooA,11 | 33.0比较fooB1和fooB2内存地址:不相等!
Process finished with exit code 0
反面教材:
最后,我给出我上面提出到最后要给出的反面例子。
随便写一个,在CloneFooA 的基础上做了少许改动,内容如下:
public class CloneFooA implements Cloneable {
&&& private String strA;
&&& private int intA;
&&& public CloneFooA(String strA, int intA) {
&&&&&&& this.strA = strA;
&&&&&&& this.intA = intA;
&&& public String getStrA() {
&&&&&&& return strA;
&&& public void setStrA(String strA) {
&&&&&&& this.strA = strA;
&&& public int getIntA() {
&&&&&&& return intA;
&&& public void setIntA(int intA) {
&&&&&&& this.intA = intA;
&&&& * @return 创建并返回此对象的一个副本。
&&&& * @throws CloneNotSupportedException
&&& public Object clone() throws CloneNotSupportedException {
&&&&&&& //直接调用父类的clone()方法,返回克隆副本
&&&&&&& return super.clone();
&&&& * @return 返回运行时的对象
&&& public CloneFooA getInstance(){
&&& public static void main(String args[]){
&&&&&&& CloneFooA fooA=new CloneFooA("aa",11);
&&&&&&& System.out.println(fooA.getStrA()+"& "+fooA.getIntA());
&&&&&&& CloneFooA fooA1=fooA.getInstance();
&&&&&&& System.out.println(fooA1.getStrA()+"& "+fooA1.getIntA());
&&&&&&& if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等!");
&&&&&&& System.out.println("-------------------------");
&&&&&&& //改变后fooA或者fooA1中任何一个,看看另外一个是否会改变
&&&&&&& fooA1.setStrA("bb");
&&&&&&& System.out.println(fooA.getStrA()+"& "+fooA.getIntA());
&&&&&&& System.out.println(fooA1.getStrA()+"& "+fooA1.getIntA());
&&&&&&& if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了");
运行结果:
aa& 11aa& 11fooA和fooA1内存地址相等!-------------------------bb& 11bb& 11fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了
Process finished with exit code 0
&本文出自 “” 博客,转载请与作者联系!
了这篇文章
类别:┆阅读(0)┆评论(0)
21:32:04 01:32:50 15:52:30 10:11:24 11:35:30 20:44:31 18:37:59 09:32:04 09:48:09 09:59:00 19:46:25 19:49:51}

我要回帖

更多关于 吉林市五月花最低消费 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信