卖模板的网站,wordpress是,动画设计师证怎么考,安卓sdk下载文章目录 前言原型模式一、浅拷贝1、案例2、引用数据类型 二、深拷贝1、重写clone()方法2、序列化 总结 前言
先看一下传统的对象克隆方式#xff1a;
原型类#xff1a;
public class Student {private String name;public Student(String name) {this.name name;}publi… 文章目录 前言原型模式一、浅拷贝1、案例2、引用数据类型 二、深拷贝1、重写clone()方法2、序列化 总结 前言
先看一下传统的对象克隆方式
原型类
public class Student {private String name;public Student(String name) {this.name name;}public String getName() {return name;}Overridepublic String toString() {return Student{name name }, hashCode this.hashCode();}
}克隆
Test
public void test(){//原型对象Student student new Student(张三);//克隆对象Student student1 new Student(student.getName());Student student2 new Student(student.getName());Student student3 new Student(student.getName());System.out.println(原型对象: student);System.out.println(克隆对象1: student1);System.out.println(克隆对象2: student2);System.out.println(克隆对象3: student3);
}优点是比较好理解简单易操作在创建新的对象时总是需要重新获取原始对象的属性如果创建的对象比较复杂时效率较低总是需要重新初始化对象而不是动态地获得对象运行时的状态, 不够灵活。 原型模式
原型模式(Prototype模式)是指用原型实例指定创建对象的种类并且通过拷贝这些原型创建新的对象原型模式是一种创建型设计模式允许一个对象再创建另外一个可定制的对象无需知道如何创建的细节工作原理是: 通过将一个原型对象传给那个要发动创建的对象这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建即 对象.clone()。 用一个已经创建的实例作为原型通过复制该原型对象来创建一个和原型对象相同的新对象。 原型模式包含如下角色
抽象原型类规定了具体原型对象必须实现的的 clone() 方法。具体原型类实现抽象原型类的 clone() 方法它是可被复制的对象。访问类使用具体原型类中的 clone() 方法来复制新的对象。 原型模式的克隆分为浅克隆和深克隆。
浅克隆创建一个新对象新对象的属性和原来对象完全相同对于非基本类型属性仍指向原有属性所指向的对象的内存地址。深克隆创建一个新对象属性中引用的其他对象也会被克隆不再指向原有对象地址。 一、浅拷贝
1、案例
对于上文中的克隆方法加以改进
原型类
public class Student implements Cloneable {private String name;public Student(String name) {System.out.println(原型对象创建成功);this.name name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return Student{name name }, hashCode this.hashCode();}//实现对象克隆Overrideprotected Object clone() throws CloneNotSupportedException {System.out.println(克隆成功);return super.clone();}
}测试
Test
public void test1() throws CloneNotSupportedException {Student newStudent new Student(张三);Student cloneStudent (Student) newStudent.clone();System.out.println(原型对象: newStudent);System.out.println(克隆对象: cloneStudent);
}2、引用数据类型 上述案例中我们可以看出克隆是克隆成功了并且没有走构造方法所克隆出的对象地址和原对象地址不一样是新的对象 对于数据类型是基本数据类型的成员变量浅拷贝会直接进行值传递也就是将该属性值复制一份给新的对象 但是引用数据类型的成员变量比如说成员变量是某个数组、某个类的对象等,并没有new 一个新的对象而是进行引用传递指向原有的引用 在这种情况下在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
我们添加原型类的成员变量
School:
public class School {private String name;public School(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}Student:
public class Student implements Cloneable {private String name;private School school;public Student(String name, School school) {this.name name;this.school school;}public void setName(String name) {this.name name;}public School getSchool() {return school;}Overridepublic String toString() {return Student{name name , school school.getName() }, Student.hashCode this.hashCode() , name.hashCode name.hashCode() , School.hashCode school.hashCode();}//实现对象克隆Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}测试
Test
public void test2() throws CloneNotSupportedException {Student newStudent new Student(张三, new School(清华));Student cloneStudent (Student) newStudent.clone();System.out.println(原型对象 newStudent);System.out.println(克隆对象 cloneStudent);System.out.println(修改克隆对象信息);cloneStudent.setName(李四);cloneStudent.getSchool().setName(北大);System.out.println(修改后的原型对象 newStudent);System.out.println(修改后的克隆对象 cloneStudent);
}上述案例可以看出
克隆确实产生新的对象但是引用数据类型只是进行了引用传递以至于我们修改了cloneStudent的学校newStudent也随之修改了那为什么String也是引用数据类型cloneStudent的那么由“张三”改为“李四”而newStudent没有呢那是因为String不可变传入新的当然指向新的地址了。 二、深拷贝 复制对象的所有基本数据类型的成员变量值 为所有引用数据类型的成员变量申请存储空间并复制每个引用数据类型成员量所引用的对象直到该对象可达的所有对象。也就是说对象进行深拷贝要对整个对象进行拷贝 深拷贝实现方式有两种 - 重写clone方法来实现深拷贝 - 通过对象序列化实现深拷贝(推荐)
1、重写clone()方法 重写clone方法主要是在原有的克隆的基础上将引用数据类型再进行嵌套克隆 每个被引用的类也要实现Cloneable接口重写clone()方法 这对全新的类来说不是很难但对已有的类进行改造时需要修改其源代码违背开闭原则。
School
public class School implements Cloneable{private String name;public School(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}Student
public class Student implements Cloneable {private String name;private School school;public Student(String name, School school) {this.name name;this.school school;}public void setName(String name) {this.name name;}public School getSchool() {return school;}Overridepublic String toString() {return Student{name name , school school.getName() }, Student.hashCode this.hashCode() , name.hashCode name.hashCode() , School.hashCode school.hashCode();}//实现对象克隆Overrideprotected Object clone() throws CloneNotSupportedException {//克隆基本数据类型以及StringStudent student (Student) super.clone();//引用数据类型再进行克隆student.school (School) student.getSchool().clone();return student;}
}测试
Test
public void test3() throws CloneNotSupportedException {Student newStudent new Student(张三, new School(清华));Student cloneStudent (Student) newStudent.clone();System.out.println(原型对象 newStudent);System.out.println(克隆对象 cloneStudent);System.out.println(修改克隆对象信息);cloneStudent.setName(李四);cloneStudent.getSchool().setName(北大);System.out.println(修改后的原型对象 newStudent);System.out.println(修改后的克隆对象 cloneStudent);
}2、序列化
涉及到的所有类必须实现Serializable接口否则会抛NotSerializableException异常。
School
public class School implements Serializable{private String name;public School(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}
}Student
public class Student implements Serializable {private String name;private School school;public Student(String name, School school) {this.name name;this.school school;}public void setName(String name) {this.name name;}public School getSchool() {return school;}Overridepublic String toString() {return Student{name name , school school.getName() }, Student.hashCode this.hashCode() , name.hashCode name.hashCode() , School.hashCode school.hashCode();}public Student deepClone() {ByteArrayOutputStream bos null;ObjectOutputStream oos null;ByteArrayInputStream bis null;ObjectInputStream ois null;try {//序列化bos new ByteArrayOutputStream();oos new ObjectOutputStream(bos);oos.writeObject(this);//反序列化bis new ByteArrayInputStream(bos.toByteArray());ois new ObjectInputStream(bis);return (Student) ois.readObject();} catch (Exception e) {e.printStackTrace();return null;} finally {try {if (bos ! null) bos.close();if (oos ! null) oos.close();if (bis ! null) bis.close();if (ois ! null) ois.close();} catch (IOException e) {e.printStackTrace();}}}
}测试
Test
public void test4() throws CloneNotSupportedException {Student newStudent new Student(张三, new School(清华));Student cloneStudent newStudent.deepClone();System.out.println(原型对象 newStudent);System.out.println(克隆对象 cloneStudent);System.out.println(修改克隆对象信息);cloneStudent.setName(李四);cloneStudent.getSchool().setName(北大);System.out.println(修改后的原型对象 newStudent);System.out.println(修改后的克隆对象 cloneStudent);
}总结
原型模式的注意事项和细节
创建新的对象比较复杂时可以利用原型模式简化对象的创建过程同时也能够提高效率不用重新初始化对象而是动态地获得对象运行时的状态如果原始对象发生变化(增加或者减少属性)其它克隆对象的也会发生相应的变化无需修改代码需要注意浅拷贝的成员变量数据类型是引用数据类型对象的时候在实现深克隆的时候可能需要比较复杂的代码建议使用序列化方式