java所有的类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制。
protected native Object clone() throws CloneNotSupportedException;
这个javabean必须实现一个标识接口,Cloneable,表明这个javabean支持复制,如果没有实现这个接口,而调用clone()方法,编译器就会抛出CloneNotSupportedException异常。java语言提供的Cloneable接口只起一个作用,就是在运行时通知虚拟机可以安全的在这个类上使用clone方法,通过调用这个clone()方法可以得到一个对象的复制(Object 类本身不实现Cloneable接口);
克隆满足的条件:
clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的有关。一般而言,clone方法满足以下条件:
1).对任何的对象x,都有:x.clone()!=x.即克隆对象与原对象不是同一个对象。
2).对任何的对象x,都有:x.clone().getClass==x.getClass(),即克隆对象与原对象的类型一样。
3).如果对象x的equals()方法定义恰当的话,x.clone().equals(x)应当是成立的。
克隆分为两种方式:深克隆和浅克隆
浅克隆(浅复制):被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深克隆(深复制):被复制对象的所有变量(非引用其他对象的变量)都含有与原来的对象相同的值,那些引用其他的对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。即:深复制把要复制的对象所引用的对象都复制了一遍,而这种堆被引用的对象的复制叫做间接复制。
以下是浅复制的例子:
====================================================================================
客户端: public class TheGreatestSage { private Monkey monkey=new Monkey(); public void change() { Monkey copy; copy=(Monkey)monkey.clone(); System.out.println("原来生日:"+monkey.getBirthday()); System.out.println("复制的生日:"+copy.getBirthday()); System.out.println("猴子是不是一个对象"+(monkey==copy)); System.out.println("金箍棒是否是一个"+(monkey.getStaff()==copy.getStaff())); } public static void main(String args[]) { new TheGreatestSage().change(); } } 猴子类(可以复制的类) import java.util.Date; public class Monkey implements Cloneable { private int height; private int weight; private GoldRingedStaff staff; private Date birthday; public Monkey() { this.birthday=new Date(); } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public GoldRingedStaff getStaff() { return staff; } public void setStaff(GoldRingedStaff staff) { this.staff = staff; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public Object clone() { Monkey temp=null; try { temp=(Monkey)super.clone(); } catch (CloneNotSupportedException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } finally { return temp; } } } 金箍棒(复制类引用的类) public class GoldRingedStaff { private float height=100.0f; private float diameter=10.0f; public void grow() { this.height*=2.0; this.diameter*=2; } public void shrink() { this.height/=2; this.diameter/=2; } public float getDiameter() { return diameter; } public void setDiameter(float diameter) { this.diameter = diameter; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } }
====================================================================================
运行结果:
原来生日:Mon May 07 09:27:12 CST 2007
复制的生日:Mon May 07 09:27:12 CST 2007
猴子是不是一个对象false
金箍棒是否是一个true
由结果可以看出:
复制的对象和原来的对象有相同的生日,而对象本身不相等。说明他们是克隆关系。 但复制的对象和原对象的金箍棒是一样的,说明二者持有的是同一个对象。
####################################################################################
深克隆例子:
为了做到深复制,所有需要复制的对象都要实现java.io.Serializable接口。
=========================================================================================
客户端 import java.io.IOException; public class TheGreatestSage { private Monkey monkey=new Monkey(); public void change() throws IOException, ClassNotFoundException { Monkey copy; copy=(Monkey)monkey.deepClone(); System.out.println("原来生日:"+monkey.getBir()); System.out.println("复制的生日:"+copy.getBir()); System.out.println("猴子是不是一个对象"+(monkey==copy)); System.out.println("金箍棒是否是一个"+(monkey.getStaff()==copy.getStaff())); } public static void main(String args[]) throws IOException, ClassNotFoundException { new TheGreatestSage().change(); } } 猴子类(可以复制的类) import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Monkey implements Cloneable,Serializable { private int height; private int weight; private GoldRingedStaff staff; private Date bir; public Monkey() { this.bir=new Date(); this.staff=new GoldRingedStaff(); } public Date getBir() { return bir; } public void setBir(Date bir) { this.bir = bir; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public GoldRingedStaff getStaff() { return staff; } public void setStaff(GoldRingedStaff staff) { this.staff = staff; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } /* * 深克隆方法 */ public Object deepClone() throws IOException, ClassNotFoundException { //首先将对象写到流里 ByteArrayOutputStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //然后将对象从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return (oi.readObject()); } /* * 浅克隆方法 */ public Object clone() { Monkey temp=null; try { temp=(Monkey)(super.clone()); } catch (CloneNotSupportedException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } return temp; } } 金箍棒(复制类引用的类) import java.io.Serializable; public class GoldRingedStaff implements Cloneable,Serializable { private float height=100f; private float diameter=10.0f; public void grow() { this.height*=2; this.diameter*=2; } public void shrink() { this.height/=2; this.diameter/=2; } public float getDiameter() { return diameter; } public void setDiameter(float diameter) { this.diameter = diameter; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } }
=========================================================================================
运行结果
原来生日:Mon May 07 10:38:21 CST 2007
复制的生日:Mon May 07 10:38:21 CST 2007
猴子是不是一个对象false
金箍棒是否是一个false
由结果可以看出:使用了深复制,除了将目标类复制,也把所有引用的的对象都复制了一遍。
===================================
===================================
===================================
===================================
java中我们可能都遇到过这样的情况,在我们将一个对象做为参数传给一个函数的时候,我们希望在这个函数中所做的操做,并不会影响到这个对象本身。但是在java传递都是引用,所以往往我们在函数内部改变了对象的某一个值,在函数外面调用该对象的时候,相应的值也同样被改变了,例如下面的程序:
class Test
{
static void myMethod(Point pt1)
{
pt1.x = 23;
System.out.println("x="+pt1.x);
}
public static void main(String[] args)
{
Point pt = new Point(2,4);
System.out.println("x="+pt.x);
myMethod(pt);
System.out.println("x="+pt.x);
}
}
class Point{
int x,y;
Point (int x,int y)
{
this.x = x;
this.y = y;
}
}
输出的结果是
x=2
x=23
x=23
但是我们想要的结果是在我们调用了函数myMethod()方法后x的值不会改变,仍然是2。由于java中的传参是引用类型,所以会出现这样的结果,我们希望传递的是对象的一份拷贝,所以这里就用到了Object的clone()方法。
克隆的实现需要一下几步:
在派生类中覆盖基类的clone()方法,并声明为public。
在派生类的clone()方法中,调用super.clone()。
在派生类中实现Cloneable接口。Cloneable接口没有任何抽象的方法,这样的成为标识接口。实现这个接口,只是为了告诉编译器这个对象可以被克隆了。我们按照上面的步骤将上面的代码修改如下:
class Test
{
static void myMethod(Point pt1)
{
pt1.x = 23;
System.out.println("x="+pt1.x);
}
public static void main(String[] args)
{
Point pt = new Point(2,4);
System.out.println("x="+pt.x);
Point pt2 = (Point)pt.clone();
myMethod(pt2);
System.out.println("x="+pt.x);
}
}
class Point implements Cloneable{
int x,y;
Point (int x,int y)
{
this.x = x;
this.y = y;
}
public Object clone()
{
Point p = null;
try
{
p = (Point)super.clone();
}
catch (Exception e)
{
e.printStackTrace();
}
return p;
}
}
输出的结果是:
x=2
x=23
x=2
首先我们在派生类中覆盖了Object类的Clone()方法,并声明为public的。然后我们调用了super.clone()方法,这里会抛出一个异常(对于这个异常大家可以自己查看java的帮助文档),所以必须用try……catch……语句捕获,然后返回此对象。这里需要说明一下,Clone()方法返回的是Object类型的,所以需要强制类型转换
对于javaclone()方法的浅析希望能给您带来帮助。
==