java 设计模式之初探原型模式

  • 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指
    向的。
    深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深
    复制进行了完全彻底的复制,而浅复制不彻底

    • 使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

    • 使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。

    • 因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

/**
*
* @功能:TODO
* @版本:1.0
* @修改:
*/
public class Prototype2 implements Cloneable,Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

private String string;
private int age;
private int[] ia;


public int[] getIa() {
    return ia;
}




public void setIa(int[] ia) {
    this.ia = ia;
}





/** 浅复制*/

public Object clone() throws CloneNotSupportedException{
    Prototype2 pro = (Prototype2)super.clone();
    return pro;

}




Prototype2() {
    super();
    // TODO Auto-generated constructor stub
}




private Prototype2(String string, int age) {
    super();
    this.string = string;
    this.age = age;
}




/* 深复制 */
 public Object deepClone() throws IOException, ClassNotFoundException {

 /* 写入当前对象的二进制流 */
 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();
 }

 public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
 public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

}

测试类:

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {

        Prototype2 p = new Prototype2();
    p.setAge(23);
    p.setString("33");
    int[] a = {1,2};
    p.setIa(a);

    Prototype2 p1 = (Prototype2) p.clone();
    System.out.println(p1.getAge());
    System.out.println("Stirng: " +p.getString().hashCode());
    System.out.println("Stirng: " +p1.getString().hashCode());
    System.out.println(p1.getIa().hashCode());
    System.out.println(p.getIa().hashCode());
    System.out.println("-----------------");
    Prototype2 p3 = (Prototype2) p.deepClone();
    System.out.println(p3.getIa().hashCode());
    System.out.println("Stirng: " +p3.getString().hashCode());
    }
}


23
Stirng: 1632
Stirng: 1632
17798304
17798304
-----------------
8236034
Stirng: 1632

从上述可以看到深复制,复制 string 类型时 他的hashcode 没有改变.
String不是基本数据类型,但是在深复制的时候并没有进行单独的复制,也就是说违反了深复制,仅仅复制了引用,而String没有实现cloneable接口,也就是说只能复制引用。

那么在修改克隆之后的对象之后,会不会将原来的值也改变了?

答案肯定是不会改变,因为String是在内存中不可以被改变的对象,就比如说在for大量循环中不推荐使用+的方式来拼凑字符串一样,每次使用+都会新分配一块内存,不在原来上修改,原来的没有指向它的引用,会被回收。所以克隆相当于1个String内存空间有两个引用,当修改其中的一个值的时候,会新分配一块内存用来保存新的值,这个引用指向新的内存空间,原来的String因为还存在指向他的引用,所以不会被回收,这样,虽然是复制的引用,但是修改值的时候,并没有改变被复制对象的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值