java编程思想阅读笔记之对象克隆

普通的对象赋值例如:对象A=对象B,是指用不同的句柄指向同一个内存空间。

我们有时候需要进行深层复制,即指向不同的内存空间,可以实现接口:Cloneable

例一:

import java.util.*; 
 
class MyObject implements Cloneable { 
 int i;  354
 MyObject(int ii) { i = ii; } 
 public Object clone() { 
 Object o = null; 
 try { 
 o = super.clone(); 
 } catch (CloneNotSupportedException e) { 
 System.out.println("MyObject can't clone"); 
 } 
 return o; 
 } 
 public String toString() { 
 return Integer.toString(i); 
 } 
} 
 
public class LocalCopy { 
 static MyObject g(MyObject v) { 
 // Passing a handle, modifies outside object: 
 v.i++; 
 return v; 
 } 
 static MyObject f(MyObject v) { 
 v = (MyObject)v.clone(); // Local copy 
 v.i++; 
 return v; 
 } 
 public static void main(String[] args) { 
 MyObject a = new MyObject(11); 
 MyObject b = g(a); 
 // Testing handle equivalence, 
 // not object equivalence: 
 if(a == b) 
 System.out.println("a == b"); 
 else 
 System.out.println("a != b"); 
 System.out.println("a = " + a); 
 System.out.println("b = " + b); 
 MyObject c = new MyObject(47); 
 MyObject d = f(c); 
 if(c == d) 
 System.out.println("c == d"); 
 else 
 System.out.println("c != d"); 
 System.out.println("c = " + c); 
 System.out.println("d = " + d); 
 } 
} 
输出:

a == b 
a = 12 
b = 12 
c != d 
c = 47 
d = 48

上述程序很简单,对象内只有普通数据成员。

例二:


/** 关于链表的深层复制
 * Created by Administrator on 2017/5/26.
 */
public class Snake extends Object implements Cloneable {
    private Snake next;
    private char c;
    // Value of i == number of segments
    Snake(int i, char x) {
        c = x;
        if(--i > 0)
            next = new Snake(i, (char)(x + 1));
    }
    void increment() {
        c++;
        if(next != null)
            next.increment();
    }
    public String toString() {
        String s = ":" + c;
        if(next != null)
            s += next.toString();
        return s;
    }
    public Snake clone() {
        Snake o = null;
        try {
            o = (Snake)super.clone();
        } catch (CloneNotSupportedException e) {}
        return o;
    }
    public static void main(String[] args) {
        Snake s = new Snake(5, 'a');
        System.out.println("s = " + s);
        Snake s2 = s.clone();
        System.out.println("s2 = " + s2);
        s.increment();
        System.out.println(
                "after s.increment, s2 = " + s2);
    }
}
 
一条Snake(蛇)由数段构成,每一段的类型都是Snake。所以,这是一个一段段链接起来的列表。所有段都是以循环方式创建的,每做好一段,都会使第一个构建器参数的值递减,直至最终为零。而为给每段赋予一个独一无二的标记,第二个参数(一个Char)的值在每次循环构建器调用时都会递增。 increment()方法的作用是循环递增每个标记,使我们能看到发生的变化;而 toString 则循环打印出每个标记。输出如下: 
 
s = :a:b:c:d:e 
s2 = :a:b:c:d:e 
after s.increment, s2 = :a:c:d:e:f 
 
这意味着只有第一段才是由Object.clone()复制的,所以此时进行的是一种“浅层复制”。若希望复制整条蛇——即进行“深层复制”——必须在被覆盖的clone()里采取附加的操作。 
通常可在从一个能克隆的类里调用 super.clone(),以确保所有基础类行动(包括Object.clone())能够进行。随着是为对象内每个句柄都明确调用一个 clone();否则那些句柄会别名变成原始对象的句柄。构建器的调用也大致相同——首先构造基础类,然后是下一个衍生的构建器……以此类推,直到位于最深层的衍生构建器。区别在于 clone()并不是个构建器,所以没有办法实现自动克隆。为了克隆,必须由自己明确进行。 

所以并不是深层复制:可以修改代码如下:

package com.myweb.Controller.test;

/** 关于链表的深层复制
 * Created by Administrator on 2017/5/26.
 */
public class Snake extends Object implements Cloneable {
    private Snake next;
    private char c;
    // Value of i == number of segments
    Snake(int i, char x) {
        c = x;
        if(--i > 0)
            next = new Snake(i, (char)(x + 1));
    }
    void increment() {
        c++;
        if(next != null)
            next.increment();
    }
    public String toString() {
        String s = ":" + c;
        if(next != null)
            s += next.toString();
        return s;
    }
    public Snake clone() {
        Snake o = null;
        try {
            o = (Snake)super.clone();
            if(o.next!=null){
                o.next=o.next.clone();
            }
        } catch (CloneNotSupportedException e) {}
        return o;
    }
    public static void main(String[] args) {
        Snake s = new Snake(5, 'a');
        System.out.println("s = " + s);
        Snake s2 = s.clone();
        System.out.println("s2 = " + s2);
        s.increment();
        System.out.println(
                "after s.increment, s2 = " + s2);
    }
}
这边是深层复制了,注意克隆方法的内部实现有所不同。

最后再介绍一下关于vector的复制,其实差不多:

class Int2 implements Cloneable {
    private int i;
    public Int2(int ii) { i = ii; }
    public void increment() { i++; }
    public String toString() {
        return Integer.toString(i);
    }
    public Object clone() {
        Object o = null;
        try {
            o = super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("Int2 can't clone");
        }
        return o;
    }
}
// Once it's cloneable, inheritance doesn't remove cloneability:
class Int3 extends Int2 {
    private int j; // Automatically duplicated
    public Int3(int i) { super(i);j=i; }
    public void increment(){
        j++;
    }
    public String toString(){
        return Integer.toString(j);
    }
}

public class AddingClone {
    public static void main(String[] args) {
        Int2 x = new Int2(10);
        Int2 x2 = (Int2)x.clone();
        x2.increment();
        System.out.println(
                "x = " + x + ", x2 = " + x2);
        // Anything inherited is also cloneable:
        Int3 x3 = new Int3(7);
        Int3 x4 = (Int3)x3.clone();
        System.out.println(x3);
        x3.increment();
        System.out.println(x3);
        System.out.println(x4);



        Vector v = new Vector();
        for(int i = 0; i < 10; i++ )
            v.addElement(new Int2(i));
        System.out.println("v: " + v);
        Vector v2 = (Vector)v.clone();
        // Now clone each element:
        for(int i = 0; i < v.size(); i++)
            v2.setElementAt(
                    ((Int2)v2.elementAt(i)).clone(), i);
        // Increment all v's elements:
        for(Enumeration e = v.elements(); e.hasMoreElements(); )
            ((Int2)e.nextElement()).increment();
        // See if it changed v's elements:
        System.out.println("v: " + v);
        System.out.println("v2: " + v2);
    }
}
必须对对象内的对象进行一一克隆,有点递归的意思,才是深层复制。从上述代码还可以看出, Int3继承了Int2,Int2实现了public clone,Int3不用重复实现,输出如下:

x = 10, x2 = 11
7
8
7
v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
v2: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]



可能有错误,欢迎指出。顺便继续看看序列化实现深层复制。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值