JAVA 中在对对象克隆的时候,可以在实体类中实现Cloneable 的接口来实现复制的功能,在实体类中重写clone()的方法,但是这样会出现一些问题,对于clone()的方法,基本数据类型是可以成功的copy的,但是对于引用数据类型,在copy的时候就会出现错误,我们用一个demo来看下到底是出现了什么样子的问题:
在这里我们直接定义了两个实体,针对批量发送邮件的时候,邮件内容可能是一样,但是针对的客户个人信息是不一样的,所以 我们进行了封装
Email实体:
//实现Cloneable 的接口
public class Email implements Cloneable, Serializable{
private String conten;//邮件内容
private String title;//邮件主题
private Customer customer;//客户实体信息
public String getConten() {
return conten;
}
public void setConten(String conten) {
this.conten = conten;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "Email{" +
"conten='" + conten + '\'' +
", title='" + title + '\'' +
", customer=" + customer +
'}';
}
//重写clone()的方法
@Override
protected Email clone() throws CloneNotSupportedException {
return (Email) super.clone();
}
Customer实体:
public class Customer , Serializable{
private String name;//客户姓名
private String address;//邮件地址
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
测试类:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Email email =new Email();
email.setConten("客户您好,我店在于7月27日有优惠活动。");
email.setTitle("优惠活动");
Customer customer=new Customer();
customer.setAddress("[email protected]");
customer.setName("zhangsan");
email.setCustomer(customer);
Email email1=email.clone();
email.getCustomer().setName("lisi");
email.getCustomer().setAddress("[email protected]");
System.out.println(email.getCustomer()==email1.getCustomer());
System.out.println(email);
System.out.println(email1);
}
}
这里我们实现的效果应该是邮件的内容是一样的,但是客户的信息是不一样的,但是我们运行的时候发现以下的结果
true
Email{conten='客户您好,我店在于7月27日有优惠活动。', title='优惠活动', customer=Customer{name='lisi', address='[email protected]'}}
Email{conten='客户您好,我店在于7月27日有优惠活动。', title='优惠活动', customer=Customer{name='lisi', address='[email protected]'}}
我们可以看到 虽然对第二个Email的Customer进行了复制,但是发现第一个Email的信息也发生了变化,并且,我们打印两者的Customer的对象 发现了 为 true,这说明了,这个对象指向的地址 是用一个地址,所以打印的信息也是一样的。
所以在Clone接口针对引用类型的属性,会指向用一个引用的地址,导致数据的错误,所以我们针对这个现象,我们在实体中自己写一个深复制的方法进行复制。
在Email的实体类中加入了一下的深克隆的方法
public Email deepClone() throws IOException, ClassNotFoundException {
//先写入
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
//在读取
ByteArrayInputStream byteArrayInputStream =new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
return (Email) objectInputStream.readObject();
}
在测试类中我们就变成了以下的,换了一下克隆的方法
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Email email =new Email();
email.setConten("客户您好,我店在于7月27日有优惠活动。");
email.setTitle("优惠活动");
Customer customer=new Customer();
customer.setAddress("[email protected]");
customer.setName("zhangsan");
email.setCustomer(customer);
Email email1=email.deepClone();
email.getCustomer().setName("lisi");
email.getCustomer().setAddress("[email protected]");
System.out.println(email.getCustomer()==email1.getCustomer());
System.out.println(email);
System.out.println(email1);
}
}
测试打印结果:
false
Email{conten='客户您好,我店在于7月27日有优惠活动。', title='优惠活动', customer=Customer{name='lisi', address='[email protected]'}}
Email{conten='客户您好,我店在于7月27日有优惠活动。', title='优惠活动', customer=Customer{name='zhangsan', address='[email protected]'}}
这样就得到了我们所预期的样子了,
不过要注意的是,在这样进行克隆的时候,实体类一定要实现 Serializable 的接口
不仅 Email要实现Serializable的接口,Customer 也需要实现Serializable的接口。
当遇到类似的场景,就不要纳闷Cloneable的接口克隆的对象是不对的了。。。哈哈哈