方式一
实现Cloneable接口,重写clone()方法
示例对象
@Data
public class User implements Cloneable,Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private List list = new ArrayList<String>();
@Override
public User clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return (User)clone;
}
}
分析:使用clone()方法进行拷贝,这种方法的优点是可以直接使用父接口的clone()方法直接拷贝一个对象,同时能够拷贝基本数据类型,但是引用数据类型不能拷贝,原对象和拷贝对象的引用属性是同一个属性,这种拷贝也就是常说的浅拷贝,测试如下
@Test
public void testNewInstance() throws IllegalAccessException, InstantiationException {
User user = new User();
user.setName("111");
User clone = user.clone();
List list = user.getList();
//给原对象中的list进行赋值
list.add("hello");
//获取拷贝对象的list属性
List cloneList = clone.getList();
Object o = cloneList.get(0);
System.out.println(clone.getName());//输出为111
System.out.println(o.toString());//输出结果为hell0,说明引用的是同一个ArrayList对象
}
方式二
使用序列化,拷贝对象实现Serializable接口,并写入serialVersionUID
分析:能够完整的拷贝对象,包括引用类型属性,但是需要自己写序列化过程,测试如下
@Test
public void testSerializable() throws Exception {
User user = new User();
user.setName("111");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(user);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
User cloneUser = (User) objectInputStream.readObject();
List list = user.getList();
list.add("hello");
List cloneUserList = cloneUser.getList();
System.out.println(cloneUserList.size());//输出为0,说明原对象list属性的改变对克隆对象的引用属性无影响,也就是不是引用的同一个对象,拷贝成功
System.out.println(cloneUser.getName());//输出111,拷贝成功
}
注意:为什么要写入serialVersionUID,主要是用于反序列化,如果没有唯一的UID,一旦原类结构发生了改变,则无法进行反序列化