设计模式之原型模式

=,浅克隆,深克隆区别

1、=

public class Student{
	int studentNo;
}
public class Client{
	public static void main(String[] args){
		Student stu1 = new Student();
		stu1.studentNo = 12345;
		Student stu2 = stu1; // 引用赋值
		System.out.println(stu2 == stu1);	// 输出true。stu1与stu2拥有完全相同的值,与克隆类似
		// 输出stu2的学号
		System.out.println(stu2.studentNo);	// 输出12345
		stu1.studentNo = 54321;	
		System.out.println(stu2.studentNO)	// 输出54321
		// 因为是引用赋值,stu2把stu1的引用地址复制了一份,指向堆内存中的同一个地址,所以stu1改变堆中的值后,stu2也会改变
	}
}

2、浅克隆
只复制基本数据类型,对于对象里的其他引用类型的数据还是复制引用地址。浅克隆要实现Cloneable接口,否则会报错。

public class Person{
	public int age;
}
public class Student implements{
	public int studentNo;
	public Person person;
	public Object clone() throw CloneNotSupportedException{
		return super.clone();
	}
}
public class Client{
	public static void main(String[] args){
		Student stu1 = new Student();
		Person person = new Person();
		person.age = 18;
		stu1.studentNo = 12345;
		stu1.person = person;

		Student stu2 = (Student) stu1.clone(); // 克隆完以后,stu2与stu1数据一样。但此时stu2中的person对象与stu1中的应用对象只想同一快堆内存,stu1中的person对象中的值改变,stu2也会随着改变,但stu2中studentNo不会在随着stu1中studentNo的值的改变而改变。
		System.out.println(stu1 == stu2); 	// false。说明stu1与stu2不在指向同一块堆空间
		System.out.println(stu2.studentNo);	//12345
		stu1.studentNo = 54321;	
		System.out.println(stu2.studentNo);	//12345。stu1中基本数据类型的改变不会影响stu2。这是浅克隆与=的区别。
		stu1.person.age = 80;
		System.out.println(stu2.person.age); // 80。stu1中引用数据类型变化,还是会影响stu2。这需要深克隆解决
	}
}

3、深克隆
深克隆有两种实现方式,一种是重写clone方法,一种是序列化(Servil)
(1)重写clone方法

public class Animal{
	public int leg;
}
public class Person implements Cloneable{
	public int age;
	public Animal animal;
	@Override
	public Object clone(){
		return super.clone();
	}
}
public class Student implemts Cloneable{
	public int studentNo;
	public Person person;
	@Override
	public Object clone(){
		this.clone = person.clone();	// 手动克隆引用对象
		return super.clone():
	}
}
public class Clinet{
	public static void main(String[] args){
		Person person = new Person();
		Student student = new student();
		Animal animal = new Animal();
		animal.leg = 2;
		person.age = 18;
		person.animal = animal;
		student.studentNo = 12345;
		student.person = person;
		Person clone = (Person) person.clone();
		
		System.out.println(clone.person.age); // 输出18
		person.age = 20;
		Syste.out.println(clone.person.age);	// 输出18。
		
		System.out.println(clone.person.animal.leg); // 输出2
		anima.leg = 4;
		System.out.println(clone.person.animal.leg);	// 输出4
	}
}

需要手动克隆每一个应用对象,若要clone的对象里有一个引用对象,这个引用对象里还有另一个对象,那么要递归的编写每一个对象的clone方法,否则只能clone重写了clone方法的对象。
(2)实现serializable接口

public class Animal implements Serializable{
	private static final long serialVersionUID = 1L;
	public int leg;
}
public class Person implements Serializable{
	private static final long serialVersionUID = 1L;
	public int age;
	public Animal animal;
}
public class Studeng implements Serializable{
	private static final long serialVersionUID = 1L;
	public int studetNo;
	public Person person;
	@Override
	public Object clone(){
		Student stu = null;
		try{
			// 对象序列化
			ByteArrayOutputStream baos = new ByteArrayOutputStram();
			ObjectOutputStream oos = new ByteArrayOutPutStram(baos);
			oos.writeObject(this);
			baos.close();
			oos.close();
			// 对象反序列化
			ByteArrayInputStram bais = new ByteArrayInputStream();
			ObjectInputStram ois = new ObjectInputStram(bais);
			stu = (Student)ois.readObject();
			bais.close();
			ois.close();
			// close操作最好在finall中。流打开后,后面操作若触发异常,流就不会关闭了
		}catch(Exception e){
		}
		return stu;
	}
}
public class Client{
	public static void main(String[] args){
		Animal animal = new Aniaml();
		animal.leg = 2;
		Person person = new Person();
		person.age = 18;
		person.animal = anliml();
		Student student = new Student();
		student.studentNo = 12345;
		student.person = person;
		Student clone = (Student) student.clone();
		animal.leg = 4;
		System.out.println(student.person.animal.leg);	// 输出4
		System.out.println(clone.person.animal.leg);	// 输出2
		person.age = 20;
		System.out.println(student.person.age);	// 输出20
		System.out.println(clone.person.age);	// 输出18
	}
}

实现Serializable接口的方式要比重写clone方法的方式更加简洁,实现Cloneable的方法,需要为每一个对象都重写clone方法。实现Serializable接口只需要重写一个clone方法即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值