写点什么

【设计模式】原型模式,java 基础入门第二版第四章课后答案

用户头像
极客good
关注
发布于: 刚刚


[](


)概念


=================================================================


原型模式是一种创建型设计模式,Prototype 模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。


也就是说,当对象的创建过于复杂的时候,我们可以通过复制的方式创建新对象,这样可以大大的提升程序的效率。


[](


)什么时候使用原型模式


=========================================================================


1.对象创建过于复杂:对象创建的时候需要经过计算、排序等操作。


2.对象时间过长:需要查询数据库或者通过 rpc 调用。


3.对象过多:比如一个集合中有一百万个对象,我现在需要修改这一百万的对象的数据,但是原数据不能动,所以这个时候使用原型模式比较适合。


具体的使用场景还是需要看项目情况而定,不能为了让代码看着高大上而去使用设计模式,比如就只有一个对象的创建(没有任何计算,没有调用数据库和 rpc),这个时候如果使用原型模式,虽然效率也会有一点点的提升,但是这样做有点得不偿失,因为还要考虑到代码的可读性和可维护性多重条件。


这么说还是比较空洞,大家可能还是不知道在什么方面使用原型模式,接下来我们将以 demo 的形式来展示什么是原型模式。


[](


)没有使用原型模式的 Demo


============================================================================


假设我 java 内存里面存放着博客的一些信息,点赞数、评论数、浏览数等等信息,现在我们有一个需求,我们需要每一个小时更新一次博客的信息,我们应该怎么做呢?


package com.ymy.test;


import com.ymy.entity.BlogStats;


import java.util.HashMap;


import java.util.Map;


public class PrototypeDesignPattern {


/**


  • 内存中存放的数据

  • key:博客 id

  • value:博客信息


*/


private static Map<Integer, BlogStats> mapCache = new HashMap<Integer, BlogStats>();


/**


  • 数据库存放的数据

  • key:博客 id

  • value:博客信息


*/


private static Map<Integer, BlogStats> mapMysql = new HashMap<Integer, BlogStats>();


/**


  • 最近一次的修改时间


*/


private static Long updateTime = 1585882804208L;


static {


BlogStats blogStats = null;


//初始化内存中 java 的博客信息


for(int i = 0; i< 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i)


.viewNum(i)


.commentNum(i)


.build();


mapCache.put(i,blogStats);


}


//初始化数据库中 java 的博客信息


for(int i = 0; i< 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i+2)


.viewNum(i+2)


.commentNum(i+2)


.build();


mapMysql.put(i,blogStats);


}


}


/**


  • 每天定时更新


*/


private static void update(){


//我们需要将数据库存放的最新数据获取出来


Map<Integer, BlogStats> newData = mapMysql;


//将新获取到的数据替换掉内存中的数据


mapCache = newData;


}


public static void main(String[] args) {


System.out.println("内存中的原始数据:"+mapCache);


//更新内存数据


update();


System.out.println("更新完之后内存中的数据:"+mapCache);


}


}


package com.ymy.entity;


import lombok.Builder;


import lombok.Getter;


import lombok.Setter;


import lombok.ToString;


@Getter


@Setter


@ToString


@Builder


public class BlogStats {


/**


  • 博客 id


*/


private Integer id;


/**


  • 博客标题


*/


private String title;


/**


  • 点赞数量


*/


private Integer likeNum;


/**


  • 浏览数量


*/


private Integer viewNum;


/**


  • 评论数


*/


private Integer commentNum;


/**


  • 更新的时间(时间戳)


*/


private Long updateTime;


}


@Getter、@Setter、@ToString、@Builder 需要引入依赖


<dependency>


<groupId>org.projectlombok</groupId>


<artifactId>lombok</artifactId>


</dependency>


上面的代码很简单,就是内存中存放了一套数据,用于展示给用户看,不是实时的,按时间段更新,更新的方式就是在数据库中获取到最新的信息,然后替换掉内存中的数据,看似很简单,但是这种方式存在着很大的问题,那就是性能问题,为什么这么说,现在只有 10 篇博客,假设存在 100w 博客呢?我们也需要在数据库中获取出来,然后再替换掉内存中的数据?这样的做法是相当不推荐的,我们想想有没有什么比较好一点的方法呢?


我们内存中的数据并不是都需要修改的,100w 数据真正需要修改的可能只有几百条或者几十条,如果从数据库全部取出替换,实在是没有必要,所以能不能,只取出变化的数据,然后做修改呢?答案是肯定的,我们一起来改造一下代码


package com.ymy.test;


import com.ymy.entity.BlogStats;


import java.util.HashMap;


import java.util.Map;


public class PrototypeDesignPattern {


/**


  • 内存中存放的数据

  • key:博客 id

  • value:博客信息


*/


private static Map<Integer, BlogStats> mapCache = new HashMap<Integer, BlogStats>();


/**


  • 数据库存放的数据

  • key:博客 id

  • value:博客信息


*/


private static Map<Integer, BlogStats> mapMysql = new HashMap<Integer, BlogStats>();


/**


  • 最近一次的修改时间


*/


private static Long updateTime = 1585882804208L;


static {


BlogStats blogStats = null;


//初始化内存中 java 的博客信息


for(int i = 0; i< 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i)


.viewNum(i)


.commentNum(i)


.status(1)


.build();


mapCache.put(i,blogStats);


}


//初始化数据库中 java 的博客信息


for(int i = 0; i<= 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i+2)


.viewNum(i+2)


.commentNum(i+2)


.status(i >= 8 ? 0 : 1)


.build();


mapMysql.put(i,blogStats);


}


}


/**


  • 每天定时更新


*/


private static void update(Map<Integer, BlogStats> changeData){


for(Map.Entry<Integer, BlogStats> entry : changeData.entrySet()){


Integer id = entry.getKey();


BlogStats blogStats = entry.getValue();


blogStats.setStatus(1);


if(mapCache.containsKey(id)){


mapCache.replace(id, blogStats);


}else{


mapCache.put(id,blogStats);


}


}


}


/**


  • 根据更新的状态获取到最新需要修改的数据

  • 由于这里仅仅只是模拟,所以这里我就随便造几条数据,你们主要看思想即可

  • @return


*/


public static Map<Integer,BlogStats> getChangeData(){


//在数据库中查询还没有更新过的数据


//由于我是模拟,所以我直接伪造了几条数据充当需要修改的数据,还请见谅


Map<Integer,BlogStats> changeDatas= new HashMap<Integer,BlogStats>();


for(Map.Entry<Integer, BlogStats> entry : mapMysql.entrySet()){


Integer id = entry.getKey();


BlogStats blogStats = entry.getValue();


if(blogStats.getStatus() == 0){


changeDatas.put(id,blogStats);


}


}


return changeDatas;


}


public static void main(String[] args) {


print(mapCache);


//获取修改的数据


Map<Integer, BlogStats> changeData = getChangeData();


//更新内存数据


update(changeData);


//将修改的博客状态改为 1 并写回数据库,这段省略


System.out.println("更新过后=====================");


print(mapCache);


}


private static void print( Map<Integer, BlogStats> map ){


for(Map.Entry<Integer, BlogStats> entry : map.entrySet()){


System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());


}


}


}


这是改造之后的代码,解释一下上面的代码,


第一:我不在往数据库中获取所有的博客数据,而是通过一个字段 status 表示这条记录是否更新过,只查询需要更新的博客信息即可。


第二:再修改的时候需要判断再数据库中查询出来的数据是否在内存中存在,如果存在,执行修改操作,如果不存在,执行添加操作。


按照上面的思路,我们的运行结果应该是博客 id 在 0-7 的信息无变化,博客 id 在 8-9 被修改,博客 id 等于 10 的被新增,那结果是不是这样呢?我们直接来看运行结果


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, comment


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


Num=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=8, viewNum=8, commentNum=8, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=9, viewNum=9, commentNum=9, status=1)


更新过后=====================


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, commentNum=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=10, viewNum=10, commentNum=10, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=11, viewNum=11, commentNum=11, status=1)


key:10 value:BlogStats(id=10, title=java 是世界上最好的语言 10, likeNum=12, viewNum=12, commentNum=12, status=1)


Process finished with exit code 0


从打印的结果来看,id 在 0-7 的没有发生改变,8-9 发生了改变,并且新增了一条 id 为 10 的新数据,所以这次的改造时成功的,现在已经优化的很好的,但还没有使用到设计模式中的原型模式,那我们还有必要使用吗?


我们之前的操作是直接基于成员变量 mapCache,但是我们现在需求稍微做了一下改动,我现在希望,我们需要一次性计算好结果在替换掉成员变量 mapCache,而不是一次一次的替换,所以这个时候上面的这种方法就不行了,out 了,那我们应该怎么办呢?很多人都想到了


  • 第一步:从数据库中获取到 status = 1 的所有数据,也就是已经更新过的数据,这个数据和内存中的一样。

  • 第二步:查询出 status=0 的所有数据,也就是没有更新过的数据。

  • 第三步:新建一个 map 用于计算修改后的结果。

  • 第四步:将新建的 map 替换掉成员变量 mapCache。


这样基本上就大功告成了,但是你发现一个问题没有,那就是在第一步的时候会耗费大量的时间,为什么这么说呢?如果数据量过大,HashMap 的存储是需要进行 hash 的计算以及还有可能发生的 hash 碰撞,所以对象的创建会耗费大量的时间,我们的内存中又存在着一份和我们数据库中差不多的数据,为什么我们不使用它来进行操作呢?这个时候你可能疑惑了,不是说不能对他进行修改吗,要等所有数据修改完成之后一次性替换吗?这个时候原型模式就要上场了。


[](


)原型模式两大数据拷贝


=========================================================================


不知道大家有没有听过这句话,new 出来的在堆里,引用的在栈中,那我们一起来看看 Java 的两种拷贝模式,浅拷贝和深拷贝。


[](


)浅拷贝




浅拷贝就是拷贝指向对象的指针(java 中的引用地址),意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误。


我们来画个图说明一下,算了,不画了,实在找不到比较好的画图工具,画的太难看了,还不如直接讲,如果有好的画图工具,可以评论告诉我哦,十分感谢。


通俗一点来说,浅拷贝就是拷贝数据的引用地址,并没有拷贝真正的数据,也就是说,拷贝出来的对象和原始对象共享一套数据,也就是说拷贝的数据发生改变,原数据也会发生改变,原数据发生改变,拷贝的数据也会发生改变,因为他们共享一套数据。


下面我们使用浅拷贝来实现一下我们上面的 demo,由于 Map 是没有 clone()方法的,所以我需要将之前的 Map 改成 HashMap,请看 demo


package com.ymy.test;


import com.ymy.entity.BlogStats;


import java.util.HashMap;


import java.util.Map;


public class PrototypeDesignPattern {


/**


  • 内存中存放的数据

  • key:博客 id

  • value:博客信息


*/


private static HashMap<Integer, BlogStats> mapCache = new HashMap<Integer, BlogStats>();


/**


  • 数据库存放的数据

  • key:博客 id

  • value:博客信息


*/


private static HashMap<Integer, BlogStats> mapMysql = new HashMap<Integer, BlogStats>();


/**


  • 最近一次的修改时间


*/


private static Long updateTime = 1585882804208L;


static {


BlogStats blogStats = null;


//初始化内存中 java 的博客信息


for(int i = 0; i< 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i)


.viewNum(i)


.commentNum(i)


.status(1)


.build();


mapCache.put(i,blogStats);


}


//初始化数据库中 java 的博客信息


for(int i = 0; i<= 10 ;++i){


blogStats = BlogStats.builder()


.id(i)


.title("java 是世界上最好的语言"+i)


.likeNum(i+2)


.viewNum(i+2)


.commentNum(i+2)


.status(i >= 8 ? 0 : 1)


.build();


mapMysql.put(i,blogStats);


}


}


/**


  • 每天定时更新


*/


private static void update(Map<Integer, BlogStats> changeData){


//这是浅拷贝


HashMap<Integer,BlogStats> oldData = (HashMap<Integer, BlogStats>) mapCache.clone();


for(Map.Entry<Integer, BlogStats> entry : changeData.entrySet()){


Integer id = entry.getKey();


BlogStats blogStats = entry.getValue();


blogStats.setStatus(1);


if(oldData.containsKey(id)){


BlogStats bs = oldData.get(id);


bs.setLikeNum(blogStats.getLikeNum());


bs.setViewNum(blogStats.getViewNum());


bs.setCommentNum(blogStats.getCommentNum());


}else{


oldData.put(id,blogStats);


}


}


System.out.println("克隆的 HashMap 最终结果如下=====================");


print(oldData);


System.out.println("克隆对象修改完成之后,原数据如下================");


print(mapCache);


mapCache = oldData;


}


/**


  • 根据更新的状态获取到最新需要修改的数据

  • 由于这里仅仅只是模拟,所以这里我就随便造几条数据,你们主要看思想即可

  • @return


*/


public static Map<Integer,BlogStats> getChangeData(){


//在数据库中查询还没有更新过的数据


//由于我是模拟,所以我直接伪造了几条数据充当需要修改的数据,还请见谅


Map<Integer,BlogStats> changeDatas= new HashMap<Integer,BlogStats>();


for(Map.Entry<Integer, BlogStats> entry : mapMysql.entrySet()){


Integer id = entry.getKey();


BlogStats blogStats = entry.getValue();


if(blogStats.getStatus() == 0){


changeDatas.put(id,blogStats);


}


}


return changeDatas;


}


public static void main(String[] args) {


System.out.println("内存中最开始存在的数据");


print(mapCache);


//获取修改的数据


Map<Integer, BlogStats> changeData = getChangeData();


//更新内存数据


update(changeData);


//将修改的博客状态改为 1 并写回数据库,这段省略


System.out.println("更新过后内存中的数据=====================");


print(mapCache);


}


private static void print( Map<Integer, BlogStats> map ){


for(Map.Entry<Integer, BlogStats> entry : map.entrySet()){


System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());


}


}


}


这里面做的修改就是使用了一个局部变量 oldData 接收 mapCache 克隆结果,然后对克隆的结果做修改,代码中使用的 mapCache.clone()属于浅拷贝,之前说过浅拷贝的数据是共享的,那我们对拷贝过后的数据进行修改,那原数据会不会受到影响呢?我们一起看打印结果


内存中最开始存在的数据


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, commentNum=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=8, viewNum=8, commentNum=8, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=9, viewNum=9, commentNum=9, status=1)


克隆的 HashMap 最终结果如下=====================


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, commentNum=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=10, viewNum=10, commentNum=10, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=11, viewNum=11, commentNum=11, status=1)


key:10 value:BlogStats(id=10, title=java 是世界上最好的语言 10, likeNum=12, viewNum=12, commentNum=12, status=1)


克隆对象修改完成之后,原数据如下================


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, commentNum=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=10, viewNum=10, commentNum=10, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=11, viewNum=11, commentNum=11, status=1)


更新过后内存中的数据=====================


key:0 value:BlogStats(id=0, title=java 是世界上最好的语言 0, likeNum=0, viewNum=0, commentNum=0, status=1)


key:1 value:BlogStats(id=1, title=java 是世界上最好的语言 1, likeNum=1, viewNum=1, commentNum=1, status=1)


key:2 value:BlogStats(id=2, title=java 是世界上最好的语言 2, likeNum=2, viewNum=2, commentNum=2, status=1)


key:3 value:BlogStats(id=3, title=java 是世界上最好的语言 3, likeNum=3, viewNum=3, commentNum=3, status=1)


key:4 value:BlogStats(id=4, title=java 是世界上最好的语言 4, likeNum=4, viewNum=4, commentNum=4, status=1)


key:5 value:BlogStats(id=5, title=java 是世界上最好的语言 5, likeNum=5, viewNum=5, commentNum=5, status=1)


key:6 value:BlogStats(id=6, title=java 是世界上最好的语言 6, likeNum=6, viewNum=6, commentNum=6, status=1)


key:7 value:BlogStats(id=7, title=java 是世界上最好的语言 7, likeNum=7, viewNum=7, commentNum=7, status=1)


key:8 value:BlogStats(id=8, title=java 是世界上最好的语言 8, likeNum=10, viewNum=10, commentNum=10, status=1)


key:9 value:BlogStats(id=9, title=java 是世界上最好的语言 9, likeNum=11, viewNum=11, commentNum=11, status=1)


key:10 value:BlogStats(id=10, title=java 是世界上最好的语言 10, likeNum=12, viewNum=12, commentNum=12, status=1)


Process finished with exit code 0


我们来看:克隆的 HashMap 最终结果如下=====================



修改了两行,新增了一行,从上面的打印结果可以看出原数据也发生了相应的变化



虽然克隆对象中新增的对象没有在原对象中增加,但是修改的属性在原对象中也发生了改变,使用浅拷贝的同学一定要注意这一点。


所以浅拷贝就不能实现我们的需求了,前面还有一个深拷贝还没有说,那它能不能满足我们的要求 呢?


[](


)深拷贝




一个引用对象一般来说由两个部分组成:一个具名的 Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名 Handle 的内部对象。它在 Manged Heap(托管堆)中分配,一般由新增引用对象的 New 方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是 Value(值)对象,如预定义类型 Int32,Double,以及结构(struct),枚举(Enum)等。


根据介绍来说,深度拷贝是可以满足我们需求的,那我们因该如何实现深拷贝呢?


序列化


序列化很好理解,就是将对象序列化,然后再反序列化,这两步之后就会得到一个全新的对象。


核心代码


/**


  • 深拷贝

  • @param obj

  • @return


*/


private static Object deepColne(Object obj) {


try {


ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();


ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);


objectOutputStream.writeObject(obj);


ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());


ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);


return objectInputStream.readObject();


} catch (IOException e) {


e.printStackTrace();


} catch (ClassNotFoundException e) {


e.printStackTrace();


}


return null;


}


这个就是通过序列化再反序列化的核心代码,然后再看一下完整 demo


package com.ymy.test;


import com.ymy.entity.BlogStats;

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
【设计模式】原型模式,java基础入门第二版第四章课后答案