原形模式Prototype,指用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
基本思路是定义一个类,实现Cloneable接口,调用clone方法。
这就涉及到java中的深拷贝和浅拷贝。
Object类里的clone()方法仅仅用于浅拷贝(拷贝基本成员属性,对于引用类型仅返回指向改地址的引用)
public static void main(String[] args) throws CloneNotSupportedException { List<String> addr1 = new ArrayList<>(); addr1.add("北京市朝阳区"); addr1.add("北京市海淀区"); Person p1 = new Person("张三",30, addr1); Person p2 = (Person) p1.clone(); System.out.println("p1:" + p1.toString()); //p1:[张三,30,[北京市朝阳区, 北京市海淀区],] System.out.println("p2:" + p2.toString()); //p2:[张三,30,[北京市朝阳区, 北京市海淀区],] p1.setAge(50); p1.getHouseList().add("北京市通城区"); System.out.println("p1:" + p1.toString()); //p1:[张三,50,[北京市朝阳区, 北京市海淀区, 北京市通城区],] System.out.println("p2:" + p2.toString()); //p2:[张三,30,[北京市朝阳区, 北京市海淀区, 北京市通城区],]
//p2中clone方法已经把基本数据类型age的值拷贝完了,所以p1或p2的age再改变的时候,另外一个对象的age是不变的。
//但是list类型传的是引用,p1与p2的list是堆中的同一个对象 p2.setAge(70); p2.getHouseList().add("武汉市江汉区"); System.out.println("p1:" + p1.toString()); //p1:[张三,50,[北京市朝阳区, 北京市海淀区, 北京市通城区, 武汉市江汉区],] System.out.println("p2:" + p2.toString()); //p2:[张三,70,[北京市朝阳区, 北京市海淀区, 北京市通城区, 武汉市江汉区],] }
class Person implements Cloneable{
private String name;
private Integer age;
private List<String> houseList;
}
如果想要实现深拷贝,需要在Person类中重写clone方法,这样拷贝之后就不会出现p1与p2修改值后互相影响的现象。
class Person implements Cloneable{ private String name; private Integer age; private ArrayList<String> houseList; public Person(String name, int age, ArrayList<String> houseList) { this.name = name; this.age = age; this.houseList = houseList; } @Override public Object clone() throws CloneNotSupportedException { Person p = (Person) super.clone(); p.houseList = (ArrayList<String>) houseList.clone(); return p; } }