原型模式
用于克隆对象。
应用场景:
- 因为拷贝要比重新创建一个对象快得多,所以当创建一个对象所耗资源很多时,可以考虑使用拷贝。
- 防止原对象被修改,例如在并发环境下的一个ArrayList,若需要修改其中的值又怕会引起并发修改异常,可以考虑克隆后操作,即保护性拷贝。
浅拷贝
实现Cloneable接口,重写clone()方法。
public class Sheep implements Cloneable{
private String id;
private String name;
private int age;
private Sheep friend;
public Sheep() {
}
public Sheep(String id, String name, int age, Sheep friend) {
this.id = id;
this.name = name;
this.age = age;
this.friend = friend;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"id='" + id + ''' +
", name='" + name + ''' +
", age=" + age +
", friend=" + friend +
'}';
}
@Override
public Sheep clone() throws CloneNotSupportedException {
return (Sheep) super.clone();
}
}
测试
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep();
sheep.setAge(1);
sheep.setName("teddy");
sheep.setFriend(new Sheep("1","tom",1,null));
Sheep cloneSheep=sheep.clone();
System.out.println(sheep);
System.out.println(cloneSheep);
System.out.println(sheep.hashCode());
System.out.println(cloneSheep.hashCode());
System.out.println(sheep.getFriend().hashCode());//引用是同一个
System.out.println(cloneSheep.getFriend().hashCode());
}
}
输出
Sheep{id='null', name='teddy', age=1, friend=Sheep{id='1', name='tom', age=1, friend=null}}
Sheep{id='null', name='teddy', age=1, friend=Sheep{id='1', name='tom', age=1, friend=null}}
1956725890
356573597
1735600054
1735600054
说明浅拷贝无法克隆引用。
深拷贝
一、使用clone()
同样实现Cloneable()接口,
将clone方法修改为
@Override
public Sheep clone(){
Sheep sheep=null;
try {
sheep=(Sheep) super.clone();
Sheep friendSheep = sheep.getFriend();
if (friendSheep!=null){
sheep.setFriend(friendSheep.clone());
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
注意:引用类型克隆前要判空。
测试输出:
Sheep{id='null', name='teddy', age=1, friend=Sheep{id='1', name='tom', age=1, friend=null}}
Sheep{id='null', name='teddy', age=1, friend=Sheep{id='1', name='tom', age=1, friend=null}}
607635164
529116035
242481580
1627800613
二、序列化
public Sheep deepClone(){
ByteArrayOutputStream out;
ByteArrayInputStream in = null;
ObjectInputStream oin = null;
ObjectOutputStream oout=null;
out = new ByteArrayOutputStream();
try {
oout=new ObjectOutputStream(out);
oout.writeObject(this);
//要保证out中有内容写入,不然会报EOFException
in = new ByteArrayInputStream(out.toByteArray());
oin=new ObjectInputStream(in);
return (Sheep) oin.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (oin!=null) {
oin.close();
}
if (oout!=null){
oout.close();
}
out.close();
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
流程:
- 实例化ByteArrayOutputStream;
- 实例化ObjectOutputStream;
- 写入对象
- 实例化ByteArrayInputStream
- 实例化ObjectInputStream
- 读出对象
注意:写入对象一定要在实例化输入流之前,因为实例化ByteArrayInputStream传入输出流,以输出流中的内容读出对象,若输出流中没有内容,会在实例化ByteArrayInputStream时抛出EOFException。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。