Java学习笔记14
Object类是所有类、数组、枚举类的父类,是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括
数组)都实现这个类的方法。
Object类实现了以下方法:
我们来看看源码中clone()方法是如何定义的:
protected native Object clone() throws CloneNotSupportedException;
为 true。x.clone() != x
也为 true,但这些并非必须要满足的要求。x.clone().getClass() == x.getClass()
为true,但这并非必须要满足的要求。x.clone().equals(x)
按照惯例,返回的对象应该通过调用super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约
定,则 x.clone().getClass() == x.getClass()。
按照惯例,此方法返回的对象应该独立于该对象(正被复制的对象)。要获得此独立性,在super.clone 返回对象
之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被复制对象的内部“深层结构”的
所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那
么通常不需要修改 super.clone 返回的对象中的字段。
Object 类的clone 方法执行特定的复制操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出
CloneNotSupportedException。注意,所有的数组都被视为实现接口Cloneable。否则,此方法会创建此对象的类的
一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有
被自我复制。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。
Object 类本身不实现接口Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。
将以上内容进行总结,得出:
1、实现Cloneable接口。
2、重载clone()方法。
3、实现clone()方法时通过super.clone();调用Object实现的clone()方法来得到该对象的副本。
接着我们来看看clone()方法的两种克隆方式:
克隆的对象:
public class CloneObject implements Serializable{ private String name ; public String getName() { return name; } public void setName(String name) { this.name = name; } }
(1)浅度克隆:
public class SimpleClone implements Cloneable ,Serializable { public CloneObject cloneObject = null; public SimpleClone(CloneObject cloneObject) { this.cloneObject = cloneObject; } public Object clone() { SimpleClone newSimpleClone = null; try { newSimpleClone = (SimpleClone)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return newSimpleClone; } }
浅度克隆测试:
public class TestClone { public static void main(String[] arg) { CloneObject obj1 = new CloneObject(); obj1.setName("cloneOne"); CloneObject obj2 = new CloneObject(); obj2.setName("cloneTwo"); SimpleClone simpleClone1 = new SimpleClone(obj1); SimpleClone simpleClone2 = new SimpleClone(obj2); simpleClone2 = (SimpleClone)simpleClone1.clone(); simpleClone2.cloneObject.setName("cloneThree"); System.out.println(simpleClone1.cloneObject.getName()); System.out.println(simpleClone2.cloneObject.getName()); } }测试结果:
cloneThree
cloneThree
以上程序创建了两个对象obj1和obj2,并分别为name赋值“cloneOne”和“cloneTwo”,然后分别赋值给定义的两个
实现浅度克隆的类。我们看到以上程序为simpleClone1进行了克隆,并将克隆后的对象赋值给simpleClone2,之后
再对simpleClone进行重新赋值。最后我们看输出的结果,发现,simpleClone1.cloneObject.getName是随着
simpleClone2改变而改变,也就是说浅度克隆仅仅克隆了该对象的所有Field值,并没有对引用类型的Field值所引用
的对象进行克隆,实际上克隆的对象指向的还是同一个块内存地址。
(2)深度克隆:
public class DepthClone { public final static Object objectCopy(Object oldObj) { Object newObj = null; try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(oldObj); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi= new ObjectInputStream(bi); newObj = oi.readObject(); } catch (IOException e) { e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); } return newObj; } }
深度克隆测试:
public class TestClone { public static void main(String[] arg) { CloneObject obj1 = new CloneObject(); obj1.setName("cloneOne"); CloneObject obj2 = new CloneObject(); obj2.setName("cloneTwo"); SimpleClone simpleClone1 = new SimpleClone(obj1); SimpleClone simpleClone2 = new SimpleClone(obj2); simpleClone2 = (SimpleClone)DepthClone.objectCopy(simpleClone1); simpleClone2.cloneObject.setName("cloneThree"); System.out.println(simpleClone1.cloneObject.getName()); System.out.println(simpleClone2.cloneObject.getName()); } }
测试结果:
cloneOne
cloneThree
以上程序通过Java的对象序列化机制,将对象的状态转换成字节流,接着通过这些值再生成新的对象,最后我们
发现,simpleClone1.cloneObject.getName是不随着simpleClone2改变而改变,也就是说simpleClone1
和simpleClone2是被存在两个不同内存中。在使用 Java的序列化时,值得注意的是,如果这个类做了改动,然后
重新编译,那么这是反序列化刚才的对象就会产生异常,这时可以通过添加serialVersionUID属性来解决。
转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/43908709 情绪控_
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。