Java對象的淺拷貝和深拷貝&&String類型的賦值


Java中的數據類型分為基本數據類型和引用數據類型。對於這兩種數據類型,在進行賦值操作方法傳參返回值時,會有值傳遞和引用(地址)傳遞的差別。

淺拷貝(Shallow Copy):

①對於數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復制一份給新的對象。因為是兩份不同的數據,所以對其中一個對象的該成員變量值進行修改,不會影響另一個對象拷貝得到的數據。

②對於數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那么淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內存地址)復制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值。

注:String類型通過常量賦值時相當於基本數據類型,通過new關鍵字創建對象時便是引用數據類型

以下情況下均是對象的淺拷貝:

(1)拷貝構造函數

(2)普通重寫clone()方法(使用clone方法的類必須實現Cloneable接口,否則會拋出異常CloneNotSupportedException)

深拷貝

首先介紹對象圖的概念。設想一下,一個類有一個對象,其成員變量中又有一個對象,該對象指向另一個對象,另一個對象又指向另一個對象,直到一個確定的實例。這就形成了對象圖。

對於深拷貝,不僅要復制對象的所有基本數據類型的成員變量值,還要為所有引用數據類型的成員變量申請存儲空間,並復制每個引用數據類型成員變量所引用的對象,直到該對象可達的所有對象。也就是說,要對整個對象圖進行拷貝

簡單地說,深拷貝對引用數據類型的成員變量的對象圖中所有的對象都開辟了內存空間;而淺拷貝只是傳遞地址指向,新的對象並沒有對引用數據類型創建內存空間。

因為創建內存空間和拷貝整個對象圖,所以深拷貝相比於淺拷貝速度較慢並且花銷較大。

以下情況下均是對象的深拷貝:

(1)對象圖中所有對象均重寫clone()方法來實現深拷貝:對象圖的每一層的每一個對象都實現Cloneable接口並重寫clone方法,最后在最頂層的類的重寫的clone方法中調用所有的clone方法即可實現深拷貝。簡單的說就是:每一層的每個對象都進行淺拷貝=深拷貝。

(2)通過對象序列化實現深拷貝

 

Java中用字符串常量賦值和使用new構造String對象的區別

String str1 = "ABC";
String str2 = new String("ABC");

String str1 = “ABC”;可能創建一個或者不創建對象,如果”ABC”這個字符串在java String池里不存在,會在java String池里創建一個創建一個String對象(“ABC”),然后str1指向這個內存地址,無論以后用這種方式創建多少個值為”ABC”的字符串對象,始終只有一個內存地址被分配,之后的都是String的拷貝,Java中稱為“字符串駐留”,所有的字符串常量都會在編譯之后自動地駐留。

String str2 = new String(“ABC”);至少創建一個對象,也可能兩個。因為用到new關鍵字,肯定會在heap中創建一個str2的String對象,它的value是“ABC”。同時如果這個字符串再java String池里不存在,會在java池里創建這個String對象“ABC”

String str1 = new String("ABC");
String str2 = new String("ABC");
System.out.println(str1 == str2); //false

String str3 = "ABC";
String str4 = "ABC";
String str5 =  "AB" + "C";
System.out.println(str3 == str4);   //true
System.out.println(str3 == str5);  // true


String a  = "ABC";
String b = "AB";
String c = b + "C";
System.out.println( a == c );//false

注意最后一個a與c相等的判斷:a、b在編譯時就已經被確定了,而c是引用變量,不會在編譯時就被確定運行時b與“C”的拼接是通過StringBuilder(JDK1.5之前是StringBuffer)實現的,最后調用的StringBuilder的toString函數返回一個新的String對象

應用的情況:建議在平時的使用中,盡量使用String = “abcd”;這種方式來創建字符串,而不是String = new String(“abcd”);這種形式,因為使用new構造器創建字符串對象一定會開辟一個新的heap空間,而雙引號則是采用了String intern(字符串駐留)進行了優化,效率比構造器高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM