wordpress 搜索 404/seo工具网站
文章目录
- 什么是原型模式
- 原型模式结构
- 原型模式的克隆种类
- 案例
- 验证为什么是浅克隆
- 深克隆
- 代码下载
什么是原型模式
原型模式就是:
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的对象。
原型模式结构
原型模式的结构包含以下几类:
- 抽象原型类:规定具体原型对象必须实现的clone()方法
- 具体原型类:实现抽象原型类的clone()方法
- 访问类(测试类):使用具体原型类中的clone()方法,用于复制新的对象
原型模式的克隆种类
原型模式的克隆,分为深克隆
和浅克隆
两种类型。
-
浅克隆:
创建一个新对象
,新对象的属性和原来对象的属性完全相同,对于非基本数据类型(引用数据类型),新克隆中的属性任然指向原对象属性所指向的对象内存地址
。相当于
快捷方式
。 -
深克隆:
创建一个新对象
,但新对象中的引用的其他对象也会被克隆,不会再指向原对象属性的内存地址
。相当于
复制文件
。
在Java语言中,Object 类中提供有 clone() 方法来实现浅克隆
。
【注意:】这里的 浅克隆或者深克隆,影响的是引用对象的地址指向。
深浅克隆都是新建对象,只是对象里的引用型成员变量是否复制的区别。
案例
编写一个测试代码案例,了解原型模式
到底是个啥?
package prototype.demo1;/*** 原型模式*/
public class Realizetype implements Cloneable {private String name;public String getName() {return name;}public Realizetype(String name) {System.out.println("有参构造 创建对象");this.name = name;}@Overridepublic Object clone() throws CloneNotSupportedException {System.out.println("clone() 方法调用,克隆新对象");return super.clone();}
}
class Test{public static void main(String[] args) throws CloneNotSupportedException {Realizetype realizetype = new Realizetype("xiangjiao");System.out.println("-->"+realizetype);// 用一个已经创建的实例作为原型,// 通过复制该原型对象// 来创建一个和原型对象相同的对象。Realizetype clone = (Realizetype) realizetype.clone();System.out.println("===>"+clone);System.out.println("===>"+clone.getName());}
}
代码执行后,控制台信息输出如下所示:
【注意:】
在Java语言中,Object 类中提供有 clone() 方法来实现浅克隆
。
为什么是浅克隆?
区分深 / 浅 克隆
的依据在于其对象中的引用对象类型
地址是否改变。
引用对象类型:非基本数据类型。
接下来就来验证为啥是浅克隆
!
验证为什么是浅克隆
既然深/浅克隆
的判断依据是其中的引用对象类型
地址信息是否相同
。
那么就创建一个
People类
,作为原型类
中的对象类型
。
如下所示:
package prototype.demo2;public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public People(String name) {this.name = name;}public People() {}
}
创建新的原型对象
,其中使用已经定义好的People对象类型
,如下所示:
package prototype.demo2;public class Realizetype2 implements Cloneable{private Integer num;// 引用对象类型private People people;public Integer getNum() {return num;}public void setNum(Integer num) {this.num = num;}public People getPeople() {return people;}public void setPeople(People people) {this.people = people;}public Realizetype2(Integer num, People people) {System.out.println("有参构造");this.num = num;this.people = people;}public Realizetype2() {System.out.println("无参构造");}@Overridepublic Realizetype2 clone() throws CloneNotSupportedException {System.out.println("clone() 调用");return (Realizetype2) super.clone();}
}
编写测试类。
1、实例化原型对象
Realizetype2
2、实例化引用对象People
,并设定数据值。
3、使用Realizetype2
的clone()
,克隆出新的对象,获取其中的People
类型信息。
4、打印其内存地址信息,判断地址信息是否匹配。
package prototype.demo2;public class Test {public static void main(String[] args) throws CloneNotSupportedException {People xiangjiao = new People("xiangjiao");System.out.println("-->"+xiangjiao);Realizetype2 realizetype2 = new Realizetype2();realizetype2.setPeople(xiangjiao);realizetype2.setNum(11);Realizetype2 clone = realizetype2.clone();People people = clone.getPeople();System.out.println("-->"+people);}
}
代码执行完毕后,控制台打印数据信息如下所示:
【发现:】
克隆的对象和被克隆对象中的
People
类,内存地址一致!
深克隆
既然浅克隆中,多个新对象中的引用对象
都是同一个地址的对象
,那么在实际使用中会出现多种不可控问题,比如下列案例:
package prototype.demo2;public class Test2 {public static void main(String[] args) throws CloneNotSupportedException {// 创建引用对象,并赋予值People people = new People();people.setName("xiangjiao");// 创建原型对象,并给其设定People类型值Realizetype2 realizetype2 = new Realizetype2();realizetype2.setPeople(people);// 克隆新对象Realizetype2 clone = realizetype2.clone();// 获取克隆对象中的 People 对象People people1 = clone.getPeople();// 将name参数值变更people1.setName("banana");// 打印People类型数据值System.out.println(realizetype2.getPeople().getName());System.out.println(clone.getPeople().getName());}
}
当代码执行后,可以从控制台中发现:
两个不同对象,People中的数据被替换了!
要想解决该问题,则需要使用到深克隆
,深克隆实现的方式很多,这里采取操作流
的形式进行展示。
package prototype.demo2;import java.io.*;public class DeepTest {public static void main(String[] args) throws Exception {// 创建引用对象,并赋予值People people = new People();people.setName("xiangjiao");// 创建原型对象,并给其设定People类型值Realizetype2 realizetype2 = new Realizetype2();realizetype2.setPeople(people);// 创建输出流对象,将 Realizetype2 对象以流的形式保存至 文件中String path = System.getProperty("user.dir")+ File.separator+"src"+File.separator+ "prototype" +File.separator+"demo2"+File.separator+"a.txt";System.out.println("path-->"+path);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));// 将对象写入文件中oos.writeObject(realizetype2);// 释放流oos.close();// 从文件中读取流ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));Realizetype2 clone2 = (Realizetype2) ois.readObject();ois.close();clone2.getPeople().setName("banana");System.out.println(realizetype2.getPeople().getName());System.out.println(clone2.getPeople().getName());}
}
代码执行后,控制台打印输出如下所示:
【注意:】由于使用流将对象保存至文件中,对应的类一定需要序列化!
public class Realizetype2 implements Cloneable, Serializable
public class People implements Serializable
代码下载
gitee 代码案例下载地址