赞
踩
使用Object中的clone方法,必须实现Cloneable接口才可以调用clone()方法,否则抛出CloneNotSupportedException异常,深拷贝也需要实现Cloneable接口,同时其成员变量为引用类型的也需要实现Cloneable接口,然后重写clone方法。Cloneable接口是一个空接口,记作他是一个标记接口,实现Cloneable接口的类被标记为可以被clone的类。
代码示例:
import java.util.ArrayList; import java.util.List; /** * @Author Long * @Date 2023/9/9 11:32 */ public class People implements Cloneable { private String name; private String age; private Info info; // 是一个对象,也必须继续拷贝 /** * 深拷贝 * * @return Info */ public People deepClone() { People people; try { people = (People) super.clone(); people.info = this.info.deepClone(); } catch (CloneNotSupportedException exception) { people = null; System.out.println("clone Info error: " + exception); } return people; } } class Info implements Cloneable { private String address; private List<String> familyMember = new ArrayList<>(); /** * 深拷贝 * * @return Info */ public Info deepClone() { Info info; try { info = (Info) super.clone(); info.familyMember = new ArrayList<>(); info.familyMember.addAll(this.familyMember); } catch (CloneNotSupportedException exception) { info = null; System.out.println("clone Info error: " + exception); } return info; } }
如上述代码示例,若People的属性不止三个,这时如果想得到一份数据一样但是完全独立的对象,则可以使用深拷贝的方式,相当于复制对象。且People中存在Info引用对象,则Info也得继续实现拷贝,才是真正实现的深拷贝,否则复制出来的Info是指向同一个内存对象,即为浅拷贝。
使用序列化的方式来复制对象 对象需要继承Serializable接口。先将对象序列化,然后再反序列化成新的对象。
Serializable 接口是一个标记接口,不用实现任何方法,仅用于标识可序列化的语义。
反序列化实现 Serilaziable 接口的类并不会调用构造方法。反序列的对象是由 JVM(java虚拟机) 以存储的二进制位为基础来构造,不通过构造方法生成。
对象是序列化的作用:
序列化步骤:
步骤一:创建一个 ObjectOutputStream 输出流;
步骤二:调用 ObjectOutputStream 对象的 writeObject() 输出可序列化对象。
反序列化步骤:
步骤一:创建一个 ObjectInputStream 输入流;
步骤二:调用 ObjectInputStream 对象的 readObject() 得到序列化的对象。
代码示例:
import java.io.Serializable; public class User implements Serializable { private String name; private Address2 address; public User(String name, Address2 address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address2 getAddress() { return address; } public void setAddress(Address2 address) { this.address = address; } /** * 深拷贝 * * @return Object */ public User deepClone() throws Exception { // 序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); // 反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (User) ois.readObject(); } } class Address2 implements Serializable { private String city; private String country; public Address2(String city, String country) { this.city = city; this.country = country; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } @Override public String toString() { return "Address2{" + "city='" + city + '\'' + ", country='" + country + '\'' + '}'; } }
class Test { public static void main(String[] args) { try { // 创建一个 ObjectOutputStream 输出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\person.txt")); // 第一次序列化 person 对象 Person person = new Person("涛涛", 21); oos.writeObject(person); // 第二次序列化 person oos.writeObject(person); // 创建一个 ObjectInputStream 输入流 ObjectInputStream ios = new ObjectInputStream(new FileInputStream("D:\\person.txt")); // 依次反序列化出 p1、p2 Person p1 = (Person) ios.readObject(); Person p2 = (Person) ios.readObject(); // 判断 p1、p2 是否是同一对象 int i1 = System.identityHashCode(p1); int i2 = System.identityHashCode(p2); System.out.println("i1 = " + i1); System.out.println("i2 = " + i2); } catch (Exception e) { e.printStackTrace(); } } } >>> 输出结果: i1 = 1349393271 i2 = 1349393271
serializable 接口的注意事项:
深拷贝与浅拷贝就是原型设计模式的两种实现方式。
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同,在这种情况下可以利用对已有对象(原型)进行复制(拷贝)的方式来创建新对象,以达到节省创建时间的目的,这种基于原型来创建对象的方式就叫做原形设计模式,简称原形模式。
实际上创建对象包含的申请内存、给成员变量赋值这一过程本身并不会花费太多时间,或者说对于大部分业务系统来说,这些时间完全是可以忽略的,应用一个复杂的模型只得到一点点的性能提升,就是所谓的过渡设计、得不偿失。
但是如果对象中的数据需要经过复杂的计算才能得到,(比如排序、计算哈希值),或者需要从PC网络,数据库,文件系统等非常慢速的io中读取,这种情况下就可以使用原型模式从其他已有对象中直接拷贝得到,而不用每次在创建新对象的时候都重复执行这些耗时的操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。