您的位置:首页 > 编程语言 > Java开发

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

2017-05-26 10:37 393 查看
普通的对象赋值例如:对象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]

可能有错误,欢迎指出。顺便继续看看序列化实现深层复制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  对象 克隆