找什么人做公司网站,wordpress个人主页源码,网站广告源码,怎么查找网站后台一、前言 我们知道在Java中存在这个接口Cloneable#xff0c;实现该接口的类都会具备被拷贝的能力#xff0c;同时拷贝是在内存中进行#xff0c;在性能方面比我们直接通过new生成对象来的快#xff0c;特别是在大对象的生成上#xff0c;使得性能的提升非常明显。然而我们…一、前言 我们知道在Java中存在这个接口Cloneable实现该接口的类都会具备被拷贝的能力同时拷贝是在内存中进行在性能方面比我们直接通过new生成对象来的快特别是在大对象的生成上使得性能的提升非常明显。然而我们知道拷贝分为深拷贝和浅拷贝之分但是浅拷贝存在对象属性拷贝不彻底问题。下面我们就具体来看一下深浅拷贝问题。 二、定义 首先来看看浅拷贝和深拷贝的定义 浅拷贝使用一个已知实例对新创建实例的成员变量逐个赋值这个方式被称为浅拷贝。 深拷贝当一个类的拷贝构造方法不仅要复制对象的所有非引用成员变量值还要为引用类型的成员变量创建新的实例并且初始化为形式参数实例值。这个方式称为深拷贝。 也就是说浅拷贝只复制一个对象传递引用不能复制实例。而深拷贝对对象内部的引用均复制它是创建一个新的实例并且复制实例。 对于浅拷贝当对象的成员变量是基本数据类型时两个对象的成员变量已有存储空间赋值运算传递值所以浅拷贝能够复制实例。但是当对象的成员变量是引用数据类型时就不能实现对象的复制了。 三、浅拷贝 我们先看如下代码
public class Person implements Cloneable{/** 姓名 **/private String name;/** 电子邮件 **/private Email email;public String getName() {return name;}public void setName(String name) {this.name name;}public Email getEmail() {return email;}public void setEmail(Email email) {this.email email;}public Person(String name,Email email){this.name name;this.email email;}public Person(String name){this.name name;}protected Person clone() {Person person null;try {person (Person) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return person;}
}public class Client {public static void main(String[] args) {//写封邮件Email email new Email(请参加会议,请与今天12:30到二会议室参加会议...);Person person1 new Person(张三,email);Person person2 person1.clone();person2.setName(李四);Person person3 person1.clone();person3.setName(王五);System.out.println(person1.getName() 的邮件内容是 person1.getEmail().getContent());System.out.println(person2.getName() 的邮件内容是 person2.getEmail().getContent());System.out.println(person3.getName() 的邮件内容是 person3.getEmail().getContent());}
}输出结果
张三的邮件内容是请与今天12:30到二会议室参加会议...
李四的邮件内容是请与今天12:30到二会议室参加会议...
王五的邮件内容是请与今天12:30到二会议室参加会议... 在该应用程序中首先定义一封邮件然后将该邮件发给张三、李四、王五三个人由于他们是使用相同的邮件并且仅有名字不同所以使用张三该对象类拷贝李四、王五对象然后更改下名字即可。程序一直到这里都没有错但是如果我们需要张三提前30分钟到即把邮件的内容修改下
public class Client {public static void main(String[] args) {//写封邮件Email email new Email(请参加会议,请与今天12:30到二会议室参加会议...);Person person1 new Person(张三,email);Person person2 person1.clone();person2.setName(李四);Person person3 person1.clone();person3.setName(王五);person1.getEmail().setContent(请与今天12:00到二会议室参加会议...);System.out.println(person1.getName() 的邮件内容是 person1.getEmail().getContent());System.out.println(person2.getName() 的邮件内容是 person2.getEmail().getContent());System.out.println(person3.getName() 的邮件内容是 person3.getEmail().getContent());}
} 在这里同样是使用张三该对象实现对李四、王五拷贝最后将张三的邮件内容改变为请与今天12:00到二会议室参加会议...。但是结果是
张三的邮件内容是请与今天12:00到二会议室参加会议...
李四的邮件内容是请与今天12:00到二会议室参加会议...
王五的邮件内容是请与今天12:00到二会议室参加会议... 这里我们就疑惑了为什么李四和王五的邮件内容也发送了改变呢让他们提前30分钟到人家会有意见的 其实出现问题的关键就在于clone()方法上我们知道该clone()方法是使用Object类的clone()方法但是该方法存在一个缺陷它并不会将对象的所有属性全部拷贝过来而是有选择性的拷贝基本规则如下 1、 基本类型如果变量是基本很类型则拷贝其值比如int、float等。 2、 对象如果变量是一个实例对象则拷贝其地址引用也就是说此时新对象与原来对象是公用该实例变量。 3、 String字符串若变量为String字符串则拷贝其地址引用。但是在修改时它会从字符串池中重新生成一个新的字符串原有紫都城对象保持不变。 四、深拷贝 基于上面上面的规则我们很容易发现问题的所在他们三者公用一个对象张三修改了该邮件内容则李四和王五也会修改所以才会出现上面的情况。对于这种情况我们还是可以解决的只需要在clone()方法里面新建一个对象然后张三引用该对象即可
protected Person clone() {Person person null;try {person (Person) super.clone();person.setEmail(new Email(person.getEmail().getObject(),person.getEmail().getContent()));} catch (CloneNotSupportedException e) {e.printStackTrace();}return person;
} 所以浅拷贝只是Java提供的一种简单的拷贝机制不便于直接使用。 对于上面的解决方案还是存在一个问题若我们系统中存在大量的对象是通过拷贝生成的如果我们每一个类都写一个clone()方法并将还需要进行深拷贝新建大量的对象这个工程是非常大的这里我们可以利用序列化来实现对象的拷贝。 五、利用序列化实现对象的深拷贝 如何利用序列化来完成对象的拷贝呢在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中再从字节流中将其读出来这样就可以创建一个新的对象了并且该新对象与母对象之间并不存在引用共享的问题真正实现对象的深拷贝。
public class CloneUtils {SuppressWarnings(unchecked)public static T extends Serializable T clone(T obj){T cloneObj null;try {//写入字节流ByteArrayOutputStream out new ByteArrayOutputStream();ObjectOutputStream obs new ObjectOutputStream(out);obs.writeObject(obj);obs.close();//分配内存写入原始对象生成新对象ByteArrayInputStream ios new ByteArrayInputStream(out.toByteArray());ObjectInputStream ois new ObjectInputStream(ios);//返回生成的新对象cloneObj (T) ois.readObject();ois.close();} catch (Exception e) {e.printStackTrace();}return cloneObj;}
} 使用该工具类的对象必须要实现Serializable接口否则是没有办法实现克隆的。
public class Person implements Serializable{private static final long serialVersionUID 2631590509760908280L;..................//去除clone()方法}public class Email implements Serializable{private static final long serialVersionUID 1267293988171991494L;....................
} 所以使用该工具类的对象只要实现Serializable接口就可实现对象的克隆无须继承Cloneable接口实现clone()方法。
public class Client {public static void main(String[] args) {//写封邮件Email email new Email(请参加会议,请与今天12:30到二会议室参加会议...);Person person1 new Person(张三,email);Person person2 CloneUtils.clone(person1);person2.setName(李四);Person person3 CloneUtils.clone(person1);person3.setName(王五);person1.getEmail().setContent(请与今天12:00到二会议室参加会议...);System.out.println(person1.getName() 的邮件内容是 person1.getEmail().getContent());System.out.println(person2.getName() 的邮件内容是 person2.getEmail().getContent());System.out.println(person3.getName() 的邮件内容是 person3.getEmail().getContent());}
}
输出结果
张三的邮件内容是请与今天12:00到二会议室参加会议...
李四的邮件内容是请与今天12:30到二会议室参加会议...
王五的邮件内容是请与今天12:30到二会议室参加会议...