1.Cloneable和Serializable
从声明中有两点是需要说明的,其也存在与其他的集合结构中Cloneable和Serializable
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {}
1.1 Cloneabale
从下面片段可以看到Cloneable接口并没有任何的方法,其是一个标志性接口,只有实现该接口的类才能调用clone()方法来复制堆上的对象而不是引用.
public interface Cloneable {}
public class CloneBean implements Cloneable {
private String name;
public CloneBean(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneBean fromCloneBean=new CloneBean("OldCloneBean");
CloneBean toCloneBean=(CloneBean)fromCloneBean.clone();
toCloneBean.setName("newCloneBean");
System.out.println(fromCloneBean.name + " vs " + toCloneBean.name);
CloneBean sameCloneBean=fromCloneBean;
sameCloneBean.setName("SameCloneBean");
System.out.println(fromCloneBean.name + " vs " + sameCloneBean.name);
}
}
//输入结果:
//OldCloneBean vs newCloneBean
//SameCloneBean vs SameCloneBean
package com.job.search.blog.code;
/**
* Created by wenyi on 16/6/3.
* Email:caowenyi@meituan.com
*/
public class CloneBean {
private String name;
public CloneBean(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneBean fromCloneBean=new CloneBean("OldCloneBean");
CloneBean toCloneBean=(CloneBean)fromCloneBean.clone();
toCloneBean.setName("newCloneBean");
System.out.println(fromCloneBean.name + " vs " + toCloneBean.name);
}
}
//输入结果:Exception in thread "main" java.lang.CloneNotSupportedException: com.job.search.blog.code.CloneBean
Java中对象保存于堆上,而引用保存于栈中,因此CloneBean sameCloneBean=fromCloneBean是两个不同名字的引用作用于同一个对象上,因此任意一个引用更改对象都要影响另外一个。为了真正的产生两个对象就需要使用继承于Object的clone()方法。从实验二可以看出如果不在类上生命其是Cloneable的,在调用clone()方法时会产生异常。
另外上面的只是一种浅拷贝,其并不会拷贝对象的field中的对象,而是引用间的赋值。从下面的实验一可以看出CloneBean中的UserBean还是在copy引用,对任意CloneBean中的UserBean的操作都会影响两个CloneBean.
深层次的拷贝,除了要拷贝对象本身还要拷贝对象域中的每个一个对象
public class CloneBean implements Cloneable {
private String name;
private UserBean userBean;
public CloneBean(String name, UserBean userBean) {
this.name = name;
this.userBean = userBean;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
String name = "CloneBeanName";
UserBean userBean = new UserBean("OldUserBean");
CloneBean fromCloneBean = new CloneBean(name, userBean);
CloneBean toCloneBean = (CloneBean) fromCloneBean.clone();
toCloneBean.name="NewBeanName";
userBean.setName("NewUserBean");
System.out.println(fromCloneBean.name + "_" + fromCloneBean.userBean + " vs " + toCloneBean.name + "_" + toCloneBean.userBean);
}
}
//输入结果:CloneBeanName_NewUserBean vs NewBeanName_NewUserBean
package com.job.search.blog.code;
/**
* Created by wenyi on 16/6/3.
* Email:caowenyi@meituan.com
*/
public class CloneBean implements Cloneable {
private String name;
private UserBean userBean;
public CloneBean(String name, UserBean userBean) {
this.name = name;
this.userBean = userBean;
}
@Override
protected Object clone() throws CloneNotSupportedException {
CloneBean cloneBean = (CloneBean) super.clone();
cloneBean.userBean = (UserBean) this.userBean.clone();
return cloneBean;
}
public static void main(String[] args) throws CloneNotSupportedException {
String name = "CloneBeanName";
UserBean userBean = new UserBean("OldUserBean");
CloneBean fromCloneBean = new CloneBean(name, userBean);
CloneBean toCloneBean = (CloneBean) fromCloneBean.clone();
toCloneBean.name = "NewBeanName";
userBean.setName("NewUserBean");
System.out.println(fromCloneBean.name + "_" + fromCloneBean.userBean + " vs " + toCloneBean.name + "_" + toCloneBean.userBean);
}
}
//输出结果:CloneBeanName_NewUserBean vs NewBeanName_OldUserBean
1.2 Serializable
对于深层拷贝除了上述所使用的方法,其也可以通过Serializable来间接实现。Seriablizable同Cloneable一样其表示该类的对象是可以被序列化到文件或者在网络流中传播,并被反序列化。
序列化代码如下:
public static <T> void writeObjectToFileName(T src, String filename) throws RuntimeException {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new FileOutputStream(new File(filename)));
out.writeObject(src);
out.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static <T> T readObjectFromFileName(String filename) throws RuntimeException {
ObjectInputStream in = null;
T dist;
try {
in = new ObjectInputStream(new FileInputStream(new File(filename)));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return dist;
}
该段代码实现的功能是将一个对象二进制编码到文件中,并同时提供了新建一个对象,并读取该对象在二进制文件中存取的数据。因此其序列化前后是两个不同的对象。注意:同Cloneable一样,任何可以序列化的对象除本身可以序列化(实现Seriable接口),其域Field也要实现Seriable接口。
如下是一个通过Seriable实现对象深层拷贝的方法:
package com.job.search.blog.code;
import java.io.*;
@SuppressWarnings("unchecked")
public abstract class BeanUtil {
public static <T> T cloneTo(T src) throws RuntimeException {
ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
ObjectOutputStream out = null;
ObjectInputStream in = null;
T dist = null;
try {
out = new ObjectOutputStream(memoryBuffer);
out.writeObject(src);
out.flush();
in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
if (in != null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return dist;
}
public static <T> void writeObjectToFileName(T src, String filename) throws RuntimeException {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(new FileOutputStream(new File(filename)));
out.writeObject(src);
out.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static <T> T readObjectFromFileName(String filename) throws RuntimeException {
ObjectInputStream in = null;
T dist;
try {
in = new ObjectInputStream(new FileInputStream(new File(filename)));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return dist;
}
public static void main(String[] args) {
CloneBean fromCloneBean = new CloneBean("OldName", new UserBean("OldUser"));
CloneBean toCloneBean = BeanUtil.cloneTo(fromCloneBean);
toCloneBean.setName("NewName");
System.out.println("Old="+fromCloneBean+" New="+toCloneBean);
}
}
//输入出结果如下:Old=com.job.search.blog.code.CloneBean@715a64e6 New=com.job.search.blog.code.CloneBean@2b237512
//OldName vs NewName
从结果中可以看出对象已将被深层次的拷贝了