原型模式就是java的克隆,这里主要讲一下java的深克隆和浅克隆。浅克隆就是只复制java对象中的基础类型,而java对象中的引用类型不会复制。深克隆就是即复制了基础类型又复制了引用类型。接下来先看一下浅克隆的列子:浅克隆很简单只要实现一下Cloneable接口然后重写一下clone方法即可:
package com.djk.clone;
/**
* 浅克隆
* @author djk
*
*/
public class ShallowCloneTest
{
public static void main(String[] args)
{
Number number = new Number();
number.setNumber(15195555);
People people = new People();
people.setAge(23);
people.setName("张三");
people.setNumber(number);
System.out.println("原始的:"+people);
People people2 = (People)people.clone();
System.out.println("克隆后的:"+people2);
//这里来验证一下浅克隆克隆的时候有没有吧people对象中的number引用指向的对象复制
people2.getNumber().setNumber(12131231);
//这里我们会发现打印出来的number值是12131231也就是拿克隆对象修改number后的值 从而证明了浅克隆的时候克隆对象里面的引用类型所指向的对象是不会复制的,引用还是指向原来的对象
System.out.println("number的值:"+number.getNumber());
}
}
class People implements Cloneable
{
private String name;
private int age;
private Number number;
public Number getNumber()
{
return number;
}
public void setNumber(Number number)
{
this.number = number;
}
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;
}
@Override
public Object clone()
{
try
{
return super.clone();
}
catch (Exception e)
{
return null;
}
}
public String toString ()
{
StringBuilder sb = new StringBuilder();
sb.append("age:").append(this.age);
sb.append("name:").append(this.name);
sb.append("number:").append(number.getNumber());
return sb.toString();
}
}
/**
* 电话
* @author djk
*
*/
class Number
{
private int number;
public int getNumber()
{
return number;
}
public void setNumber(int number)
{
this.number = number;
}
}
这个就是浅克隆,这里我也在代码里面做了一个实验看浅克隆的时候克隆对象里面的引用类型所指向的对象是否有进行了克隆,实现证明浅克隆的时候引用类型所指向的对象没有进行克隆,引用还是指向原来的对象。
接下来看一下深克隆的实现方式:
package com.djk.clone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* 深克隆
* @author djk
*
*/
public class DeepCloneTest
{
public static void main(String[] args)
{
DeepNumber deepNumber = new DeepNumber();
deepNumber.setNumber(151958);
DeepPeople deepPeople = new DeepPeople();
deepPeople.setAge(23);
deepPeople.setName("张三");
deepPeople.setDeepNumber(deepNumber);
System.out.println("克隆前的:"+deepPeople);
//克隆
DeepPeople deepPeople2 = (DeepPeople)deepPeople.getDeepObject();
System.out.println("克隆后的: "+deepPeople2);
//修改克隆对象得到DeepNumber对象的引用
deepPeople2.getDeepNumber().setNumber(11111);
//验证深克隆是否会把引用类型指向的对象进行复制,验证发现打印出来的还是原来的151958.证明深克隆的时候把克隆对象中的引用类型所指向的对象也进行了克隆
System.out.println(deepNumber.getNumber());
}
}
class DeepPeople implements Serializable
{
/**
* 序列号
*/
private static final long serialVersionUID = 8756895922228278060L;
private String name;
private int age;
private DeepNumber deepNumber;
public DeepNumber getDeepNumber()
{
return deepNumber;
}
public void setDeepNumber(DeepNumber deepNumber)
{
this.deepNumber = deepNumber;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
/**
* 利用io进行深克隆
*
* @return
*/
public Object getDeepObject()
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
catch (Exception e)
{
return null;
}
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("name:").append(this.name);
sb.append("age:").append(this.age);
sb.append("deepNumber:").append(this.deepNumber.getNumber());
return sb.toString();
}
public void setAge(int age)
{
this.age = age;
}
}
class DeepNumber implements Serializable
{
/**
* TODO 添加字段注释
*/
private static final long serialVersionUID = -1390830639552626291L;
private int number;
public int getNumber()
{
return number;
}
public void setNumber(int number)
{
this.number = number;
}
}
这是利用io来实现深克隆的一种实现方式,证明了深克隆的时候会把克隆对象中的引用类型所指向的对象也进行克隆一份。这里要注意的是克隆对象中的引用类型所指向的对象必须也实现Serializable接口。不然会报错,因为我们是利用的io来进行的操作,把整个对象放入一个字节内存中。
在这里顺便提一下当我们进行序列化的时候有时候有这样的需求,有某一个属性不需要被序列化这是我们可以这样:
private transient DeepNumber deepNumber;
加上transient关键字即可.加上这个关键字后当我们克隆的时候那么DeepNumber的这个引用将不会再被克隆。。。