一, 引用的复制和对象复制.

在编程中, 我们有时会用两个引用指向同一个对象.

例如:

ArrayList a = new ArrayLIst();
ArrayList b = a;

看起来好像有a,b两个容器, 实际上a,b是两个引用, 它们都指向同1个Object的内存地址.

而对象复制是指:

在内存里划分一块与指定对象相同内容的内存.

也就是说内存里原理有1个Object的内存, 复制后就有两个了...

二, 对象复制的简便方法.

当然, 对象复制的实现十分简单, 只需要实例化1个具有相同属性的对象就ok了.

注意, 如果用 "==" 来讲比较两个引用是返回false, 因为它们的地址不同.

举个列子:

2.1 产品类Prod:

public class Prod {private int prodID;private String prodName;public int getProdID() {return prodID;}public void setProdID(int prodID) {this.prodID = prodID;}public String getProdName() {return prodName;}public void setProdName(String prodName) {this.prodName = prodName;}@Overridepublic String toString(){return "Prod: " + this.getProdID() + " , " + this.getProdName();}
}

2.2 订单类Order:

public class Order {private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();}
}

2.3 客户端代码:

这里我先实例化1个order类 od1, 然后在复制1个od1 的对象od2

     Prod p1 = new Prod();p1.setProdID(1);p1.setProdName("Hammer");Order od1 = new Order();od1.setOrderID(1);od1.setProd(p1);od1.setAmount(20);Prod p2 = new Prod();p2.setProdID(1);p2.setProdName("Hammer");Order od2 = new Order();od2.setOrderID(1);od2.setProd(p1);od2.setAmount(20);System.out.println(od1);System.out.println(od2);

输出:

Order: 1 , 20 Prod: 1 , Hammer
Order: 1 , 20 Prod: 1 , Hammer

2.4 这种方法的缺点

首先这种写法不够优雅, 很多重复代码.

其次, 这种复制方法调用了类的构造函数.

就如上面的例子, 即使Order类的构造函数是空的, 但是实际上构造函数的执行机制很复杂,.

构造函数最重要的动作就是给类里的每个成员划分内存空间. 毕竟java是类c语言, 相当于执行了很多次malloc()函数.

如果某些业务类的构造函数写的很复杂, 就更耗费资源了.

而且

三, 利用Object.clone()方法来实现对象复制.

java里所有对象都是直接或简直继承自基类Object.

而clone()是基类的Native 方法, 所谓Native方法可以认为是java 内部特定方法, 它比非Native的执行效率要好.

也就是说, 利用Object.clone() 方法会比实例化1个相同内容对象效率要好.

3.1 Object.clone()方法和 Cloneable接口:

Object.clone() 方法有点特殊,  首先它是public方法, 也就是说它可以通过引用名和"."来调用.

但是它不能被子类继承, 也就说, 出了Object类外所有java里的class里面都没有clone()这个方法的.

如果要使用Object.clone()方法.

只能引用1个叫做 Cloneable里的Interface,  然后重写Cloneable接口里的clone()方法, 在里面调用object.clone().

这个接口就起了1个标记的作用, 帮组实现多态.

3.2 订单类Order:

我们按在这个思路来修改上面的订单类Order:

public class Order implements Cloneable{private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();}@Overridepublic Object clone(){Object o = null;try{o = super.clone();}catch(Exception e){e.printStackTrace();}return o;}
}

值得注意的是, Object.clone() 回抛异常.

而, Prod类没有任何修改.

3.3 客户端代码:

Prod p1 = new Prod();p1.setProdID(2);p1.setProdName("knife");Order od1 = new Order();od1.setOrderID(2);od1.setAmount(30);od1.setProd(p1);Order od2 = (Order)od1.clone();System.out.println(od1);System.out.println(od2);

可见, 只需要执行一句

Order od2 = (Order)od1.clone();

就相当于 复制了1个对象.

3.4 UML图

我们来看看这个例子的UML:

实际上这个就是原型模式(prototype)的UML图了,

原来我们不知不觉得使用了原型模式.

四, 原型模式的定义

原型模式(protoType), 用原型实例制定创建对象的种类, 并且通过copy这些原型创建新的对象.

总觉得设计模式的定义都太过于简单恶心了.

上面的

原型指的是  Cloneable这个接口.

原型实例指的是 Order这个类.

五, 浅复制和深复制

对象复制也分两种.

浅复制:

两个对象中的值类型成员属性相等,  对象成员成员属性实际上没有复制,都是同一个对象.

深复制:

两个对象中的值类型成员属性相等,  对象成员属性指向不同的 具有相同成员的 对象.

如上面的例子, 稍稍修改客户端代码:

     Prod p1 = new Prod();p1.setProdID(2);p1.setProdName("knife");Order od1 = new Order();od1.setOrderID(2);od1.setAmount(30);od1.setProd(p1);Order od2 = (Order)od1.clone();System.out.println(od1);System.out.println(od2);od1.setOrderID(3);od1.setAmount(40);od1.getProd().setProdName("blade");System.out.println(od1);System.out.println(od2);

上面 构建了对象od1,

然后复制出了另1个对象od2,

然后修改od1的 值成员 和 对象成员

然后输出od1, 和 od2 成员的值:

Order: 2 , 30 Prod: 2 , knife
Order: 2 , 30 Prod: 2 , knife
Order: 3 , 40 Prod: 2 , blade
Order: 2 , 30 Prod: 2 , blade

可见, 当od1 的id 和 amount的值被改成 3 和 40 后,  od2 的id和 Amount的值并不受影响, 因为它们的值类型成员属性是相互独立的.

但是当od1 的 prod属性的内容被修改后,    od2 的也被修改了(knife - > blade),  因为 od1 和 od2 的 prod成员指向的都是同1个对象.

这就证明了:

Java里的 Object.clone()方法实现的是浅复制.

六, 原型模式的深复制实现

接下来再次修改上面的例子, 令其实现成深复制

而且, 根据项目需要, 复制并不会复制Order的id, 也就是订单号码是唯一的, 只复制Prod和数量.

6.1 订单类Order:

public class Order implements Cloneable{private int orderID;private Prod prod;private int amount;public int getOrderID() {return orderID;}public void setOrderID(int orderID) {this.orderID = orderID;}public Prod getProd() {return prod;}public void setProd(Prod prod) {this.prod = prod;}public int getAmount() {return amount;}public void setAmount(int amount) {this.amount = amount;}public String toString(){return "Order: " + this.getOrderID() + " , " + this.getAmount() + " " + this.getProd().toString();}@Overridepublic Object clone(){Prod p = new Prod();p.setProdID(this.getProd().getProdID());p.setProdName(this.getProd().getProdName());Order o = new Order();o.setOrderID(this.getOrderID() + 1);o.setAmount(this.getAmount());o.setProd(p);return o;}
}

客户端输出:

Order: 2 , 30 Prod: 2 , knife
Order: 3 , 30 Prod: 2 , knife
Order: 3 , 40 Prod: 2 , blade
Order: 3 , 30 Prod: 2 , knife

可以, 无论od1修改了什么,  od2 都不受影响

这种方法放弃了Object.clone(), Order类在重写clone()方法里还是使用了构造方法去实例化1个新的对象.

这种方法配置更加灵活(选择性地复制成员)

当时放弃了Object.clone()的效能优点.

但是这仍然实现了原型模式(protoType)

原型模式(ProtoType) - Java里的对象复制相关推荐

  1. java prototype是什么,java设计模式-原型模式(Prototype)

    定义 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是原型模式的用意 原型模式的结构 原型模式要求对象实现同一个可 ...

  2. (Prototype)原型模式的Java实现(转)

    原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 当我们已经拥有某个得来不易的宝贝时,往往我们会很想再"变"一些出来,即这个宝贝的& ...

  3. Java原型模式(prototype)

      prototype模式也就是原型模式,是javaGOF23种设计模式中的一种,我们在学习spring的时候在bean标签的学习中碰到过,所以本文来给大家介绍下原型模式 原型模式   在java中我 ...

  4. Java设计模式--原型模式Prototype

    原型模式Prototype 原型模式使得用户可以通过复制对象样本来创建新对象.与通过调用构造函数创建对象相比,二者主要区别在于:通过复制创建的新对象一般会包含原始对象的某些状态. 原型模式属于对象的创 ...

  5. 设计模式-创建型模式-原型模式(Java)(创建重复对象)

    目录 原型模式 1 介绍 2 实现 具体实现步骤 原型模式 原型模式(Prototype Pattern)是⽤于创建重复的对象,同时⼜能保证性能.这种类型的设计模式属于创建型模式,它提供了⼀种创建对象 ...

  6. 设计模式(三)原型模式 Prototype

    原型模式 原型模式概念 适用场景 简单克隆 浅克隆 深克隆 破坏单例 开源工具 总结 原型模式概念 原型模式(Prototype Pattern)是指原型实例指定创建对象的 种类,并且通过拷贝这些原型 ...

  7. 设计模式(23):创建型-原型模式(Prototype)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  8. 原型模式(Prototype Pattern)

    原型模式(Prototype Pattern) 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. ...

  9. 原型模式-prototype

    一.什么是原型模式 Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例.使用Prototype模式创建的实例,具有与原型一样的数据. 二.原型模式的特点 1.由原型对 ...

最新文章

  1. IslandViewer4|基因组岛在线预测
  2. 小程序 音频API采坑完全手册
  3. 计算机学院校园文化标语,校园文化建设标语50条
  4. mac 下 通过 brew 安装 MariaDB
  5. 【Linux系统编程学习】Linux进程控制原语(fork、exec函数族、wait)
  6. ORA-01841: (完整) 年份值必须介于 -4713 和 +9999 之间, 且不为 0情况解决
  7. python最简单选课系统作业_python之路——作业:学生选课系统
  8. Bootstrap 分页导航的尺寸
  9. 蓝桥杯 ADV-13 算法提高 最小乘积(提高型)
  10. 【代码模板】不存在的NOIP2017
  11. MVC HtmlHelper listbox用法
  12. 前端开发-技术设计文档编写规范
  13. 原生JS实现Ajax请求
  14. 记一次Android机顶盒破解工程
  15. 2018 再见,你好 2019
  16. 页面动态时间php,HTML制作网页动态时钟教程
  17. 史上最全《JMeter压力测试教程》——通俗易懂,3天即可学会
  18. Linux运维跳槽必备面试题
  19. 编译工程——词法分析
  20. 代码写的太乱?一分钟教你优化

热门文章

  1. update yum 到指定版本_yum语法及常用命令汇总
  2. const 和指针赋值
  3. 4.WaitForSingleObject函数分析
  4. 【Vue】ElementUI el-select 下拉分页加载数据,并支持搜索功能(此处不支持分页)
  5. 【Laravel】连接 sqlite 数据库 Database [xxx] not exist
  6. 将数字字符串格式化为指定长度
  7. 用CMD命令实现一个简单的网页搜索
  8. mysql传不进去汉字,Mysql下插入汉字失败
  9. svg text换行_5分钟看懂SVG反爬虫原理与绕过实战 | 知了干货分享
  10. reactor线程模型_从TCP服务器到I/O模型,带你学习Netty