对象克隆

 

 

基本属性克隆

假设你想基本属性可以,可以用“=”拷贝。

七大基本类型都可以这样拷贝。(boolean,char,byte,short,float,double.long)

 但是如果你使用这个方法拷贝对象,结果就不对了。如下:

声明一个学生类:写set/get方法,并重写toString

测试:

 

如图所示:只是set了第二个学生,但是第一个学生也变了,因为=在引用对象里面只是把地址引用地址赋值给对方了。

在栈中虽然对象引用不同,但是在堆中指向的对象是同一个。

 对象的克隆

在网上看到了一篇文章,为什么要克隆对象?

(bu shi fu zhi de ,真的)

  克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的。

查过网上之后克隆分两种,浅克隆与深克隆。

先说克隆,再说区别吧。

Object的clone克隆

一般步骤是():

1. 被复制的类需要实现Cloneable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)

2. 覆盖clone()方法,访问修饰符设为public方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)

下面对上面那个类进行改造:

 

实现了Cloneable接口,并重写了clone方法,调用父类的clone方法;

 然后测试:

打印出来的,第一个学生和第二个学生不一样,改变第二个对象,第一个对象不变。经过验证地址也不一样。这样就是我们要的效果,克隆对象和原对象都彼此独立。

现在给Student添加一个引用属性:

Teacher的属性如下:

依然有效:

这里红字注意:网上很多教程讲深克隆和浅克隆,说object的clone方法,如果对象有引用属性需要递归克隆。不知是我版本问题还是其他,暂时未复现这个问题,如果不能克隆引用属性则可以进行递归克隆。

 

使用文件流克隆 

1 实现Serializable接口(序列号接口)

2 略‘

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。 

 具体操作:就在上面类改了。

下面测试类:

 

效果一样, 

来个总结吧:

实现对象克隆有两种方式:

  1). 实现Cloneable接口并重写Object类中的clone()方法;

  2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

 

流克隆公共方法

此公共方法使用了泛型,只要实现序列号接口均可克隆。

/**
     * 使用流克隆对象
     * 
     * @param t 传入对象,必须实现Serializable序列号接口
     * @return    克隆后的新对象
     */
    public static <T extends Serializable> T cloneObjectBySerializable(T t) {
        T cloneT = null;
        try { 
              // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,
              //而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              ObjectOutputStream oos = new ObjectOutputStream(baos);
              oos.writeObject(t);
              // 将流序列化成对象
              ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
              ObjectInputStream ois = new ObjectInputStream(bais);
              cloneT = (T) ois.readObject();
          } catch (IOException e) {
              e.printStackTrace();
          } catch (ClassNotFoundException e) {
              e.printStackTrace();
          }
        return cloneT;
    }

公共类里面就一个克隆方法。

下面使用测试类检验:

 

效果依然可以,

 

 

文摘自:https://www.cnblogs.com/Qian123/p/5710533.html#_label0

posted @ 2018-05-01 02:36  苦心明  阅读(136)  评论(1)    收藏  举报