日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

android 浅复制与深复制

發(fā)布時(shí)間:2024/4/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 浅复制与深复制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


今天,簡(jiǎn)單講講 

android 淺復(fù)制與深復(fù)制的內(nèi)容。


一、前言

任何變成語(yǔ)言中,其實(shí)都有淺拷貝和深拷貝的概念,Java 中也不例外。在對(duì)一個(gè)現(xiàn)有的對(duì)象進(jìn)行拷貝操作的時(shí)候,是有淺拷貝和深拷貝之分的,他們?cè)趯?shí)際使用中,區(qū)別很大,如果對(duì)其進(jìn)行混淆,可能會(huì)引發(fā)一些難以排查的問(wèn)題。

本文就在 Java 中的深拷貝和淺拷貝做一個(gè)詳細(xì)的解說(shuō)。

二、什么是淺拷貝和深拷貝

首先需要明白,淺拷貝和深拷貝都是針對(duì)一個(gè)已有對(duì)象的操作。那先來(lái)看看淺拷貝和深拷貝的概念。

在 Java 中,除了基本數(shù)據(jù)類型(元類型)之外,還存在 類的實(shí)例對(duì)象 這個(gè)引用數(shù)據(jù)類型。而一般使用 『 = 』號(hào)做賦值操作的時(shí)候。對(duì)于基本數(shù)據(jù)類型,實(shí)際上是拷貝的它的值,但是對(duì)于對(duì)象而言,其實(shí)賦值的只是這個(gè)對(duì)象的引用,將原對(duì)象的引用傳遞過(guò)去,他們實(shí)際上還是指向的同一個(gè)對(duì)象。

而淺拷貝和深拷貝就是在這個(gè)基礎(chǔ)之上做的區(qū)分,如果在拷貝這個(gè)對(duì)象的時(shí)候,只對(duì)基本數(shù)據(jù)類型進(jìn)行了拷貝,而對(duì)引用數(shù)據(jù)類型只是進(jìn)行了引用的傳遞,而沒(méi)有真實(shí)的創(chuàng)建一個(gè)新的對(duì)象,則認(rèn)為是淺拷貝。反之,在對(duì)引用數(shù)據(jù)類型進(jìn)行拷貝的時(shí)候,創(chuàng)建了一個(gè)新的對(duì)象,并且復(fù)制其內(nèi)的成員變量,則認(rèn)為是深拷貝。

所以到現(xiàn)在,就應(yīng)該了解了,所謂的淺拷貝和深拷貝,只是在拷貝對(duì)象的時(shí)候,對(duì) 類的實(shí)例對(duì)象 這種引用數(shù)據(jù)類型的不同操作而已。



三、Java 中的 clone()

3.1 Object 上的 clone() 方法

在 Java 中,所有的 Class 都繼承自 Object ,而在 Object 上,存在一個(gè) clone() 方法,它被聲明為了 protected ,所以我們可以在其子類中,使用它。

而無(wú)論是淺拷貝還是深拷貝,都需要實(shí)現(xiàn) clone() 方法,來(lái)完成操作。


它的實(shí)現(xiàn)非常的簡(jiǎn)單,它限制所有調(diào)用 clone() 方法的對(duì)象,都必須實(shí)現(xiàn) Cloneable 接口,否者將拋出 CloneNotSupportedException 這個(gè)異常。最終會(huì)調(diào)用 internalClone() 方法來(lái)完成具體的操作。而 internalClone() 方法,實(shí)則是一個(gè) native 的方法。對(duì)此我們就沒(méi)必要深究了,只需要知道它可以 clone() 一個(gè)對(duì)象得到一個(gè)新的對(duì)象實(shí)例即可。


而反觀 Cloneable 接口,可以看到它其實(shí)什么方法都不需要實(shí)現(xiàn)。對(duì)他可以簡(jiǎn)單的理解只是一個(gè)標(biāo)記,是開(kāi)發(fā)者允許這個(gè)對(duì)象被拷貝。


具體的使用很簡(jiǎn)單。

⑴clone方法將對(duì)象復(fù)制了一份并返回給調(diào)用者。一般而言,clone()方法滿足:
①對(duì)任何的對(duì)象x,都有x.clone() !=x//克隆對(duì)象與原對(duì)象不是同一個(gè)對(duì)象
②對(duì)任何的對(duì)象x,都有x.clone().getClass()= =x.getClass()//克隆對(duì)象與原對(duì)象的類型一樣
③如果對(duì)象x的equals()方法定義恰當(dāng),那么x.clone().equals(x)應(yīng)該成立。

⑵Java中對(duì)象的克隆

①為了獲取對(duì)象的一份拷貝,我們可以利用Object類的clone()方法。
②在派生類中覆蓋基類的clone()方法,并聲明為public。
③在派生類的clone()方法中,調(diào)用super.clone()。
④在派生類中實(shí)現(xiàn)Cloneable接口。


請(qǐng)看如下代碼:

public class Student implements Cloneable { String name; int age; Student(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try{ o=(Student)super.clone();//Object 中的clone()識(shí)別出你要復(fù)制的是哪一個(gè)對(duì)象。 } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } public static void main(String[] args) { Student s1=new Student("zhangsan",18); Student s2=(Student)s1.clone(); s2.name="lisi"; s2.age=20; //修改學(xué)生2后,不影響學(xué)生1的值。System.out.println("name="+s1.name+","+"age="+s1.age); System.out.println("name="+s2.name+","+"age="+s2.age);} }


說(shuō)明:
①為什么我們?cè)谂缮愔懈采wObject的clone()方法時(shí),一定要調(diào)用super.clone()呢?在運(yùn)行時(shí)刻,Object中的clone()識(shí)別出你要復(fù)制的是哪一個(gè)對(duì)象,然后為此對(duì)象分配空間,并進(jìn)行對(duì)象的復(fù)制,將原始對(duì)象的內(nèi)容一一復(fù)制到新對(duì)象的存儲(chǔ)空間中。


②繼承自java.lang.Object類的clone()方法是淺復(fù)制。以下代碼可以證明之。

class Professor { String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } } public class Student implements Cloneable { String name;// 常量對(duì)象。 int age; Professor p;// 學(xué)生1和學(xué)生2的引用值都是一樣的。 Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try{ o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } o.p=(Professor)p.clone(); return o; } public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30; System.out.println("name="+s1.p.name+","+"age="+s1.p.age);System.out.println("name="+s2.p.name+","+"age="+s2.p.age);//輸出結(jié)果學(xué)生1和2的教授成為lisi,age為30。} }


那應(yīng)該如何實(shí)現(xiàn)深層次的克隆,即修改s2的教授不會(huì)影響s1的教授?代碼改進(jìn)如下。
改進(jìn)使學(xué)生1的Professor不改變(深層次的克隆)

class Professor implements Cloneable { String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try{ o=super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } } public class Student implements Cloneable { String name; int age; Professor p; Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try{ o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } //對(duì)引用的對(duì)象也進(jìn)行復(fù)制o.p=(Professor)p.clone(); return o; } public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30; //學(xué)生1的教授不 改變。System.out.println("name="+s1.p.name+","+"age="+s1.p.age); System.out.println("name="+s2.p.name+","+"age="+s2.p.age); } }



3.利用串行化來(lái)做深復(fù)制(主要是為了避免重寫(xiě)比較復(fù)雜對(duì)象的深復(fù)制的clone()方法,也可以程序?qū)崿F(xiàn)斷點(diǎn)續(xù)傳等等功能)
??? 把對(duì)象寫(xiě)到流里的過(guò)程是串行化(Serilization)過(guò)程,但是在Java程序師圈子里又非常形象地稱為“冷凍”或者“腌咸菜(picking)”過(guò)程;而把對(duì)象從流中讀出來(lái)的并行化(Deserialization)過(guò)程則叫做 “解凍”或者“回鮮(depicking)”過(guò)程。
??? 應(yīng)當(dāng)指出的是,寫(xiě)在流里的是對(duì)象的一個(gè)拷貝,而原對(duì)象仍然存在于JVM里面,因此“腌成咸菜”的只是對(duì)象的一個(gè)拷貝,Java咸菜還可以回鮮。
??? 在Java語(yǔ)言里深復(fù)制一個(gè)對(duì)象,常??梢韵仁箤?duì)象實(shí)現(xiàn)Serializable接口,然后把對(duì)象(實(shí)際上只是對(duì)象的一個(gè)拷貝)寫(xiě)到一個(gè)流里(腌成咸菜),再?gòu)牧骼镒x出來(lái)(把咸菜回鮮),便可以重建對(duì)象。
如下為深復(fù)制源代碼。

public Object deepClone() { //將對(duì)象寫(xiě)到流里 ByteArrayOutoutStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //從流里讀出來(lái) ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject()); }


這樣做的前提是對(duì)象以及對(duì)象內(nèi)部所有引用到的對(duì)象都是可串行化的,否則,就需要仔細(xì)考察那些不可串行化的對(duì)象或?qū)傩钥煞裨O(shè)成transient,從而將之排除在復(fù)制過(guò)程之外。上例代碼改進(jìn)如下。

class Teacher implements Serializable{String name;int age;public void Teacher(String name,int age){this.name=name;this.age=age;} } public class Student implements Serializable{String name;//常量對(duì)象int age;Teacher t;//學(xué)生1和學(xué)生2的引用值都是一樣的。public void Student(String name,int age,Teacher t){this.name=name;this.age=age;this.p=p;}public Object deepClone() throws IOException,OptionalDataException,ClassNotFoundException{//將對(duì)象寫(xiě)到流里ByteArrayOutoutStream bo=new ByteArrayOutputStream();ObjectOutputStream oo=new ObjectOutputStream(bo);oo.writeObject(this);//從流里讀出來(lái)ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());ObjectInputStream oi=new ObjectInputStream(bi);return(oi.readObject());}public static void main(String[] args){ Teacher t=new Teacher("tangliang",30);Student s1=new Student("zhangsan",18,t);Student s2=(Student)s1.deepClone();s2.t.name="tony";s2.t.age=40;//學(xué)生1的老師不改變System.out.println("name="+s1.t.name+","+"age="+s1.t.age);} }



總之,可以通過(guò)重寫(xiě)clone來(lái)實(shí)現(xiàn)對(duì)象的復(fù)制,也可以通過(guò)序列號(hào)實(shí)現(xiàn)對(duì)象的復(fù)制。


android 淺復(fù)制與深復(fù)制就講完了。


就這么簡(jiǎn)單。

總結(jié)

以上是生活随笔為你收集整理的android 浅复制与深复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。