要求有一个简历类,必需要有姓名,能够设置性别和年龄,能够设置工做经历,最终须要三份简历。ide
/** * 简历类 * Created by callmeDevil on 2019/7/13. */ public class Resume { private String name; private String sex; private String age; private String timeArea; private String company; public Resume (String name) { this.name = name; } /** * 设置我的信息 * @param sex * @param age */ public void setPersonalInfo(String sex, String age){ this.sex = sex; this.age = age; } /** * 设置工做经历 * @param timeArea * @param company */ public void setWorkExperience(String timeArea, String company) { this.timeArea = timeArea; this.company = company; } /** * 显示 */ public void display () { System.out.println(String.format("%s %s %s", name, sex, age)); System.out.println(String.format("工做经历:%s %s", timeArea, company)); } // 此处省略get、set方法 }
/** * 测试 * Created by callmeDevil on 2019/7/13. */ public class Test { public static void main(String[] args) { Resume resumeA = new Resume("callmeDevil"); resumeA.setPersonalInfo("男", "24"); resumeA.setWorkExperience("2018-2019", "伟大的航道"); Resume resumeB = new Resume("callmeDevil"); resumeB.setPersonalInfo("男", "24"); resumeB.setWorkExperience("2018-2019", "伟大的航道"); Resume resumeC = new Resume("callmeDevil"); resumeC.setPersonalInfo("男", "24"); resumeC.setWorkExperience("2018-2019", "伟大的航道"); resumeA.display(); resumeB.display(); resumeC.display(); } }
callmeDevil 男 24 工做经历:2018-2019 伟大的航道 callmeDevil 男 24 工做经历:2018-2019 伟大的航道 callmeDevil 男 24 工做经历:2018-2019 伟大的航道
跟手写简历没有差异,三份简历须要三份实例化,若是客户须要二十份简历,那就得实例化二十次。性能
用原型实例指定建立对象的种类,而且经过拷贝这些原型建立新的对象。测试
/** * 简历类(实现JDK克隆接口) * Created by callmeDevil on 2019/7/13. */ public class Resume implements Cloneable{ private String name; private String sex; private String age; private String timeArea; private String company; public Resume (String name) { this.name = name; } /** * 设置我的信息 * @param sex * @param age */ public void setPersonalInfo(String sex, String age){ this.sex = sex; this.age = age; } /** * 设置工做经历 * @param timeArea * @param company */ public void setWorkExperience(String timeArea, String company) { this.timeArea = timeArea; this.company = company; } /** * 显示 */ public void display () { System.out.println(String.format("%s %s %s", name, sex, age)); System.out.println(String.format("工做经历:%s %s", timeArea, company)); } /** * 实现克隆方法,可进行本身的克隆逻辑 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // 此处省略get、set方法 }
/** * 原型模式测试 * Created by callmeDevil on 2019/7/13. */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { Resume resumeA = new Resume("callmeDevil"); resumeA.setPersonalInfo("男", "24"); resumeA.setWorkExperience("2018-2019", "伟大的航道"); // 只须要调用clone方法就能够实现新简历的生成,而且能够修改新简历的细节 Resume resumeB = (Resume) resumeA.clone(); resumeB.setWorkExperience("2019-2020", "新世界"); Resume resumeC = (Resume) resumeA.clone(); resumeC.setPersonalInfo("男", "25"); resumeA.display(); resumeB.display(); resumeC.display(); } }
callmeDevil 男 24 工做经历:2018-2019 伟大的航道 callmeDevil 男 24 工做经历:2019-2020 新世界 callmeDevil 男 25 工做经历:2018-2019 伟大的航道
在上面这个简历类中,若是字段是值类型(基本数据类型)的,则对该字段直接进行复制;若是是引用类型(String等),则/复制引用/但不/复制引用的对象/;所以,原始对象及其副本引用同一对象。this
在此以前,咱们先作一个简单的测试code
System.out.println("123" == "123"); System.out.println("123".equals("123")); System.out.println(new String("123") == new String("123")); System.out.println(new String("123").equals(new String("123")));
相信有点基础的都知道答案吧?就不卖弄了,直接上结果orm
true true false true
至于结果为何会这样,网上也许多分析,此处重点在浅复制的讲解,所以不作过多叙述。对象
带着上面的理解再看下面的内容。在可克隆的简历类例子中,基本数据类型就没什么好测试的,有兴趣的也能够将年龄改为 int 类型;对于其余 String 类型,就拿 company 字段来讲,咱们新建一个测试类看下是什么结果blog
public class Test2 { public static void main(String[] args) throws CloneNotSupportedException { Resume resumeA = new Resume("callmeDevil"); resumeA.setWorkExperience("0", "伟大的航道");// 直接声明String Resume resumeB = (Resume) resumeA.clone(); // A 与 B 的公司两种比较 System.out.println(resumeA.getCompany() == resumeB.getCompany()); System.out.println(resumeA.getCompany().equals(resumeB.getCompany())); resumeA.setWorkExperience("0", new String("伟大的航道"));//new 的方式建立String Resume resumeC = (Resume) resumeA.clone(); // A 与 C 的公司两种比较 System.out.println(resumeA.getCompany() == resumeC.getCompany()); System.out.println(resumeA.getCompany().equals(resumeC.getCompany())); } }
比对第一个“123”的例子,稍微思考下在比对下面结果看是否一致接口
true true true true
是的,这就是浅复制。不论A简历的 company 是直接声明的仍是 new 出来的,在clone方法中都只会对 company 字段复制一份引用而已。所以才会出现 “==” 和 “equal()”的结果都是“true”。对于引用类型来讲,这个字段所在类实现了clone方法是不够的,它只会对引用类型复制一份引用,那若是连引用类型的字段也要建立一份新的数据,那即是 “深复制”。get
此处不纠结于如何对上述 String 的深复制。现将简历类进行改造,把“工做经历”抽出成另外一个类 WorkExperience
/** * 简历类2(深复制) * Created by callmeDevil on 2019/7/13. */ public class Resume2 implements Cloneable { private String name; private String sex; private String age; // 工做经历 private WorkExperience work; public Resume2 (String name) { this.name = name; this.work = new WorkExperience(); } private Resume2(WorkExperience work) throws CloneNotSupportedException { this.work = (WorkExperience) work.clone(); } /** * 设置我的信息 * @param sex * @param age */ public void setPersonalInfo(String sex, String age){ this.sex = sex; this.age = age; } /** * 设置工做经历 * @param timeArea * @param company */ public void setWorkExperience(String timeArea, String company) { // 此处赋值给 work 对象 this.work.setWorkDate(timeArea); this.work.setCompany(company); } /** * 显示 */ public void display () { System.out.println(String.format("%s %s %s", name, sex, age)); // 此处显示 work 对象的值 System.out.println(String.format("工做经历:%s %s", work.getWorkDate(), work.getCompany())); } /** * 实现克隆方法,可进行本身的克隆逻辑 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { // 调用私有的构造方法,让“工做经历”对象克隆完成,而后再给这个“简历”对象 // 相关的字段赋值,最终返回一个深复制的简历对象 Resume2 obj = new Resume2(this.work); obj.setName(this.name); obj.setSex(this.sex); obj.setAge(this.age); return obj; } // 此处省略get、set方法 }
/** * 工做经历 * Created by callmeDevil on 2019/7/13. */ public class WorkExperience implements Cloneable{ private String workDate; private String company; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // 此处省略get、set方法 }
/** * 深复制测试 * Created by callmeDevil on 2019/7/13. */ public class TestDeepClone { public static void main(String[] args) throws CloneNotSupportedException { Resume2 resumeA = new Resume2("callmeDevil"); resumeA.setPersonalInfo("男", "24"); resumeA.setWorkExperience("2018-2019", "伟大的航道"); Resume2 resumeB = (Resume2) resumeA.clone(); resumeB.setWorkExperience("2019-2020", "新世界"); Resume2 resumeC = (Resume2) resumeA.clone(); resumeC.setWorkExperience("2020-XXXX", "木叶忍者村"); resumeA.display(); resumeB.display(); resumeC.display(); } }
callmeDevil 男 24 工做经历:2018-2019 伟大的航道 callmeDevil 男 24 工做经历:2019-2020 新世界 callmeDevil 男 24 工做经历:2020-XXXX 木叶忍者村
能够看到,每次克隆都能将简历类中的工做经历类一同新建,而不是单纯的同个对象进行改变内容。若是是浅复制的实现,那么在相同测试类中会出现什么结果呢?应该能猜到吧,那就是三次输出都是同样的。
对于工做经历类的浅复制实现本文就不描述了,有兴趣的能够自行测试,很简单,须要修改的地方有这么两处:
只须要更改这两处,在相同的测试类中就能看到如下结果
callmeDevil 男 24 工做经历:2020-XXXX 木叶忍者村 callmeDevil 男 24 工做经历:2020-XXXX 木叶忍者村 callmeDevil 男 24 工做经历:2020-XXXX 木叶忍者村
看到此处就不须要解释了吧,每次克隆只是新实例化了“简历”,但三个“简历”中的“工做经历”都是同一个,每次 set值 的时候都必将影响到全部对象,因此输出的工做经历都是相同的。这也同时说明了实现深复制的必要条件:
作到以上两点,便可将本来浅复制的功能转变为深复制。
原型模式无非就是对指定建立的原型实例进行复制,再对新对象另作操做,省去从新 new 的过程。其中复制便分为浅复制与深复制。