深入了解Java对象的克隆

  

今天要介绍一个概念,对象的克隆。本篇有一定难度,请先做好心理准备。看不懂的话可以多看两遍,还是不懂的话,可以在下方留的言,我会看情况进行修改和补充。

  

克隆,自然就是将对象重新复制一份,那为什么要用克隆呢?什么时候需要使用呢?先来看一个小栗子:

  

简单起见,我们这里用的是商品类的简单版本。

        公共类商品{   私人字符串标题;   私人双价格;      公共物品(字符串aTitle,双人力成本){   标题=aTitle;   价格=人力成本;   }      公共空间setPrice(双价格){   这一点。价格=价格;   }      公共空间setTitle(字符串标题){   这一点。标题=标题;   }//用于打印输出商品信息   公共空间print () {   system . out。println(“标题:”+标题+“价格:”+价格);   }   }      

然后我们来使用这个类。

        公开课GoodsTest {   公共静态void main (String [] args) {   货物goodsA=新产品(“goodsA”, 20);   货物goodsB=goodsA;   system . out。println(“在变化:”);   goodsA.print ();   goodsB.print ();      goodsB.setTitle (“GoodsB”);   goodsB.setPrice (50);   system . out。println(“后变化:”);   goodsA.print ();   goodsB.print ();   }   }      

我们创建了一个商品对象赋值给变量goodsA,然后又创建了一个商品变量,并把goodsA赋值给它,先调用产品的印刷方法输出这两个变量中的信息,然后调用商品类中的setTitle和setPrice方法来修改goodsB中的对象内容,再输出两个变量中的信息,下面是输出:

  
  

之前改变:
  标题:GoodsA价格:20.0
  标题:GoodsA价格:20.0
  后改变:
  标题:GoodsB价格:50.0
  标题:GoodsB价格:50.0

     

这里我们发现了灵异事,我们明明修改的是goodsB的内容,可是goodsA的内容也同样发生了改变,这究竟是为什么呢?别心急,且听我慢慢道来。

  

在爪哇语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int,双字节,布尔,char等简单数据类型,引用类型包括类,接口,数组等复杂类型。使用等号赋值都是进行值传递的,如将一个整数型变量赋值给另一个整数型变量,那么后者将存储前者的值,也就是变量中的整数值,对于基本类型如int,翻倍,char等是没有问题的,但是对于对象,则又是另一回事了,这里的goodsA和goodsB都是商品类对象的变量,但是它们并没有存储商品类对象的内容,而是存储了它的地址,也就相当于c++中的指针,如果对于指针不了解,那我就再举个栗子好了。我们之前举过一个栗子,把计算机比作是仓库管理员,内存比作是仓库,你要使用什么类型的变量,就需要先登记,然后管理员才会把东西给你,但如果是给你分配一座房子呢?这时候不是把房子搬起来放到登记簿粒,而是登记下房子的地址,这里的地址就是我们的类对象变量里记录的内容,所以,当我们把一个类对象变量赋值给另一个类对象变量,如goodsB=goodsA时,实际上只是把一个指向的对象地址赋值给了B,这样B也同样指向这个地址,所以这时候,goodsA和goodsB操作的是同一个对象。

  

所以,如果只是简单的赋值的话,之后对于goodsA和goodsB的操作都将影响同一个对象,这显然不是我们的本意。也许你还会问,直接再新的一个对象不就好了,确实如此,但有时候,如果我们需要保存一个goodsA的副本,那就不仅仅要新的一个对象,还需要进行一系列赋值操作才能将我们的新对象设置成跟goodsA对象一样,而且商品类越复杂,这个操作将会越繁琐,另外使用克隆方法还进行本地优化,效率上也会快很多,总而言之,就是简单粗暴。

  

那如何使用克隆呢?这里我们就要介绍我们牛逼哄哄的对象类了,所有的类都是对象类的子类,虽然我们并没有显式声明继承关系,但所有类都难逃它的魔掌,它有两个受保护的方法,其中一个就是克隆方法。

  

下面我来展示一波正确的骚操作:

     //要使用克隆方法需要实现可克隆接口   公共类商品实现可克隆{   私人字符串标题;   私人双价格;      公共物品(字符串aTitle,双人力成本){   标题=aTitle;   价格=人力成本;   }      公共空间setPrice(双价格){   这一点。价格=价格;   }      公共空间setTitle(字符串标题){   这一点。标题=标题;   }      公共空间print () {   system . out。println(“标题:”+标题+“价格:”+价格);   }//这里重载了接口的克隆方法   @Override   保护对象克隆(){   货物g=零;//这里是异常处理的语句块,可以先不用了解,只要知道是这样使用就好,之后的文章中会有详细的介绍   尝试{   g=(商品)super.clone ();   }捕捉(CloneNotSupportedException e) {   System.out.println (e.toString ());   }   返回g;   }   }

深入了解Java对象的克隆