原型模式有两种实现方法,深拷贝和浅拷贝。浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象……而深拷贝得到的是一份完完全全独立的对象。所以,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间。
也就是说浅拷贝只复制一个对象,传递引用,不能复制实例。而深拷贝对对象内部的引用均复制,它是创建一个新的实例,并且复制实例。
假如有一个对象 Object o = new Object()
,再声明一个Object o1;
如果o1要获得第一个对象,首先想到用 "="赋值,但是这个常常会和想要的不一样
class Man {
private String sex;
int age;
public Man(String sex, int age) {
this.sex = sex;
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Man{" +
"sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
浅拷贝
传递基本类型参数
public class Test {
/**
* 基本类型参数
* @param m
*/
public static void testBasicType(int m) {
System.out.println("m=" + m);
m = 100;
System.out.println("m=" + m);
}
/**
* 传递对象引用
* @param m1
*/
static void testObject(Man m1) {
System.out.println(m1);
Man d2 = m1;
d2.setAge(45);
System.out.println(m1);
}
/**
* 在这里,s引用先指向传过来的对象,接着发生改变指向新创建的对象
* @param s
*/
public static void changeRef(StringBuilder s) {
s = new StringBuilder("Java");
}
public static void main(String[] args) {
/**
* 基本类型参数
*/
int i = 50;
testBasicType(i);
System.out.println(i);
}
运行结果:
可以看到 变量 i的值 没有修改
传递 对象引用
1、
/**
* 传递对象 参数
*/
Man d1 = new Man("hehe", 25);
testObject(d1);
System.out.println(d1);
局部方法改变了对象的属性 Copy
今天被这个问题搞得头都大了,一直用等于号赋值,今天发现一些莫名其妙的错误,看了好多文章才发现,原来对象赋值不能用等于号,等于只能用于主类型的赋值(String,int,float之类),而如果是其他的类生产的对象,用等于号是映射,并非赋值,只要改了等号一边的值,另一边的也跟着变化,就是说JAVA没有开辟新的内存,只是给原来的对象再起了个名字而已。
2、
/**
* 在这里,引用 先指向传过来的对象,接着发生改变指向新创建的对象
* @param s
*/
public static void changeRef(StringBuilder s) {
s = new StringBuilder("Java");
}
/**
* 传递对象 参数
*/
Man d1 = new Man("hehe", 25);
testObject(d1);
System.out.println(d1);
这里的值没发生改变
深拷贝
第一种方法:递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止。根据这个思路对之前的代码进行重构。重构之后的代码如下所示:
public class Demo {
private HashMap<String, SearchWord> currentKeywords=new HashMap<>();
private long lastUpdateTime = -1;
public void refresh() {
// Deep copy
HashMap<String, SearchWord> newKeywords = new HashMap<>();
for (HashMap.Entry<String, SearchWord> e : currentKeywords.entrySet()) {
SearchWord searchWord = e.getValue();
SearchWord newSearchWord = new SearchWord(
searchWord.getKeyword(), searchWord.getCount(), searchWord.getLastUpdateTime());
newKeywords.put(e.getKey(), newSearchWord);
}
// 从数据库中取出更新时间>lastUpdateTime的数据,放入到newKeywords中
List<SearchWord> toBeUpdatedSearchWords = getSearchWords(lastUpdateTime);
long maxNewUpdatedTime = lastUpdateTime;
for (SearchWord searchWord : toBeUpdatedSearchWords) {
if (searchWord.getLastUpdateTime() > maxNewUpdatedTime) {
maxNewUpdatedTime = searchWord.getLastUpdateTime();
}
if (newKeywords.containsKey(searchWord.getKeyword())) {
SearchWord oldSearchWord = newKeywords.get(searchWord.getKeyword());
oldSearchWord.setCount(searchWord.getCount());
oldSearchWord.setLastUpdateTime(searchWord.getLastUpdateTime());
} else {
newKeywords.put(searchWord.getKeyword(), searchWord);
}
}
lastUpdateTime = maxNewUpdatedTime;
currentKeywords = newKeywords;
}
private List<SearchWord> getSearchWords(long lastUpdateTime) {
// TODO: 从数据库中取出更新时间>lastUpdateTime的数据
return null;
}
}
第二种方法:先将对象序列化,然后再反序列化成新的对象。具体的示例代码如下所示:
public Object deepCopy(Object object) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(object);
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
}
https://time.geekbang.org/column/article/200786