Java基础知识总结5-----克隆与序列化

Java对象的“假”克隆

实例说明

  在实际编程中,会遇到需要进行克隆技术的情况。例如要获得一个非常复杂的对象,与其使用new创建对象在对该对象进行赋值,不如直接克隆现有对象。

  本实例将演示一种常见的错误克隆方法。

关键技术

  Java中,对于今本数据类型可以使用“=”号进行克隆,此时两个变量除了相等以外是没有任何关系的。而对于引用类型是不能简单的使用“=”进行克隆。这与Java的内存空间使用有关。Java将内存空间分成两块,即栈和堆。在栈中保存基本数据类型和引用变量,在堆中保存对象。对于引用变量,使用“=”将修改引用,而不是赋值堆中对象。此时两个引用变量将指向一个对象。因此,如果一个变量对其进行修改则会该变另一个变量。

  提示:通常情况很少使用“=”操作对象,也很少使用“=”比较两个对象。

熟悉Java内存的空间分配

  Java将内存分成两个部分,即栈和堆。在栈中保存基本数据类型和引用变量,在堆中保存对象。对于栈中的变量在使用完之后会立即被回收,这样就可以继续常见其他的变量。而对于堆中的对象,是由虚拟机进行管理的,因此即使该对象已经不再使用,该内存只会在一个不确定的时间被回收。

如:
ObjectA objA = new ObjectA();
ObjectB objB = objA;
(对于引用变量而言,使用"="将修改引用,而不是复制堆中的对象,
此时两个引用变量将指向同一个对象,因此,若是一个变量对其进行修改则会改变另外一个变量)
当修改objA时,objB也被修改,故称之为"假克隆"


Java对象的浅克隆

关键技术

  Java中任何一个类都是Object类的直接或间接子类。如果一个类没有超类那么它默认继承自Object类。在Object类中实现了很多有用的方法。当克隆对象时,需要使用clone()方法。

  需要注意的是该方法是一个受保护的方法,通常需要重写该方法并将访问权限限定为public。该方法将类中的各个属性进行复制,如果对于引用类型的属性这种操作就会有问题,因此成为浅克隆。提供克隆功能的类需要实现cloneable接口,否则lone是会抛出异常CloneNotSupportedException。

浅克隆的应用

  对于类中的每个属性,如果只包括基本数据类型或者不可变的引用类型,如String,或者对象在其声明周期内不会发生变化,则可以使用浅克隆来复制对象。

  重写clone()方法,一般会先调用super.clone()进行浅复制,然后再复制那些易变对象,从而达到深复制的效果。

//浅克隆
/*
* 1.Object类中的clone()方法为protected的
* 2.需要实现克隆功能的类必须实现Cloneable接口
* */
class Kid{
    public int age = 10;
}
class Person implements Cloneable{

    public int age = 10;
    public Kid kid = new Kid();

    protected Person clone(){
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}
        Person p = new Person();
        Person clonep = p.clone();
        System.out.println("p.age:"+p.age+" p.kid.age:"+p.kid.age);
        System.out.println("clonep.age:"+clonep.age+" clonep.kid.age:"+clonep.kid.age);
/*Output:
p.age:10 p.kid.age:10
clonep.age:10 clonep.kid.age:10*/

        p.age = 15;
        p.kid.age=15;
        System.out.println("clonep.age:"+clonep.age+" clonep.kid.age:"+clonep.kid.age);
/*
Output:
clonep.age:10 clonep.kid.age:15

 

测试代码中我克隆了Person对象实例p,将Person的另一个引用clonep指向克隆后的对象。然后我先打印p和clonep的age值与其中引用对象kid的age值。随后我修改p中两者的值为15。再通过打印clonep的两者的值可以发现clonep中kid对象的age值变成了15。

这种克隆就叫做浅克隆,它可以克隆对象时,会自动克隆作用域中的基础类型(包含String类型,因为String类是不可变类,它在克隆时会自动出现拷贝一份对象)。

但是它却无法克隆引用对象,因为每一个对象在Java虚拟机中都是独立的(成员对象的类型没有实现Cloneable接口,而且Object类的clone()方法时受保护的,在克隆对象中并不能调用其成员对象的clone()方法)。

所以此时克隆出来的对象会共享其成员对象,实际上成员对象并没有发生克隆。

 


 

深克隆

clone是浅拷贝的, 在编写程序时要注意这个细节。
现在为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。如果只是用Object中默认的clone方法,是浅拷贝的,再次以下面的代码验证:
 

 

 

 static class Body implements Cloneable{
  public Head head;
  public Body() {}
  public Body(Head head) {this.head = head;}
 
  @Override
  protected Object clone() throws CloneNotSupportedException {
   Body newBody =  (Body) super.clone();
   newBody.head = (Head) head.clone();
   return newBody;
  }
 
 
 

 static class Head implements Cloneable{
  public  Face face;
  
  public Head() {}
  public Head(Face face){this.face = face;}
  @Override
  protected Object clone() throws CloneNotSupportedException {
   //return super.clone();
   Head newHead = (Head) super.clone();
   newHead.face = (Face) this.face.clone();
   return newHead;
  }
 }
 
 static class Face implements Cloneable{
  @Override
  protected Object clone() throws CloneNotSupportedException {
   return super.clone();
  }
 }
得到的运行结果如下:
body == body1 : false
body.head == body1.head : false
body.head.face == body1.head.face : false

 

如果您看到这里还是有很多疑问请参考以下链接:

Java中的clone方法:

https://blog.csdn.net/zhangjg_blog/article/details/18369201?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf

 


对象序列化实现深克隆

 


 

序列化:指堆内存中的java对象数据,通过某种方式把对存储到磁盘文件中,或者传递给其他网络节点(网络传输)。这个过程称为序列化,通常是指将数据结构或对象转化成二进制的过程.

(即将对象转化为二进制,用于保存,或者网络传输.)

反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程.

序列化详解:

https://blog.csdn.net/tree_ifconfig/article/details/82766587?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.add_param_isCf

序列化Serializable详解:

https://blog.csdn.net/weixin_30718391/article/details/96966088?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.add_param_isCf

 

 

 

 

你能看到这儿,说明...你迫切想要开始码代码了,所以最后再附赠书上的代码截屏一张:

posted on 2020-10-02 13:06  冬至初一来  阅读(82)  评论(0)    收藏  举报

导航