1、Clone方法
1.1、不使用clone方法
Employee tobby = newEmployee(“CMTobby”,5000);
Employee cindyelf = tobby;
這樣的操作只是淺複製,tobby和cindyelf指向內存中同一個Employee類型對象,tobby.setSalary改變salary值之後,cindyelf.getSalary獲取的就是salary改變之後的值。
1.2、使用clone方法
注意:
- 調用clone方法的對象類必須實現(implements)clonable接口,否則的話就會拋出CloneNotSupportedException,同時爲了能是其他類能調用這個類的clone方法,最好將clone方法改爲public
這裏調用的clone相當於調用的是父類Object的方法,父類方法是protected,很顯然不能這樣調用。
這裏因爲MyObject重寫了方法,雖然還是protected,但是test1與MyObject在同一個包裏面,所以可以調用。
- Object類中就有clone方法(protected),但是Object又沒有實現clonable接口,所以Object不能直接調用clone方法
- 執行clone方法時首先會判斷是否實現clonable接口,否則拋出錯誤
如果自定義類使用super.clone()方法調用object默認的clone方法,這樣只是得到的一個淺複製,即基本類型直接複製一個值到複製類中,複製類中對基本類型數據改變不會影響被複制類中基本類型的值;而對於引用類型,只會複製一個引用,指向的還是被複制類中的引用對象,在複製類中對引用的改變會改變被複制類中引用變量的內容。
如果自定義類自己定義深複製,則需要新建一個引用對象,將被複制類中的引用變量的內容全部複製過來。
2、相等性判斷
2.1、==
在java中利用“==”比較變量時,系統使用變量在棧中所存的值進行比較,所以:
- 對於基本變量,就是比較變量的內容值
- 對於引用類型變量,則比較的是所指向的對象的地址
- 對於java.net.URL類,聯網狀態下直接比較url地址字符串;如果聯網狀態下則比較對應的IP地址
2.2、equals
equals只能應用於引用變量(String除外,String比較的值內容),Object類中equals方法的定義如下:
boolean equals(Object o){
return this==o;
}
所以使用系統默認的equals方法時,還是比較的地址值,而不是對象內容值。
爲了能比較對象內容的值,則必須在自定義類中對equals進行重寫,同時最好也要將hashcode也進行重寫(需要注意hashcode的特性——每次new一個object,這個object的hashcode是永遠不同的,這樣的話可能會影響equals的比較,關於hashcode具體的介紹見:http://fhuan123.iteye.com/blog/1452275)。
重寫的一般步驟:
CloneObject obj = new CloneObject();
obj.clone(); // Compile ok
publicboolean equals(Object o){
//重寫equals方法,後面最好重寫hashCode方法
if(this == o) //這樣效率高
returntrue;
if(o ==null)
returnfalse;
if( !(oinstanceof CloneObject))
returnfalse;
final CloneObject co = (CloneObject)o;
// 變量具體比較操作
3、instanceof、getclass()判斷類對象
publicclass InstanceofGetclassDiffextends parent{
publicstatic void main(String[] args)
{
InstanceofGetclassDiffa = newInstanceofGetclassDiff();
parentb = newparent();
System.out.println(ainstanceof parent); //輸出true
System.out.println(binstanceof InstanceofGetclassDiff); //輸出false
System.out.println(a.getClass() == b.getClass());//輸出false
}
}
class parent{}
可以看出instanceof可以判斷繼承關係,即“子類實例 instanceof 父類名稱”這個模式,而getClass無法判斷繼承關係,只是簡單的判斷是否是一類。推廣到Equals方法中的應用,當子類中自定義Equals時,則最好用getClass方法,反之如果所有子類都繼承父類的Equals方法,則用instanceof。
4、String對象
4.1、Java內存分析
- 棧(Stack) :存放基本類型的變量數據和對象的引用,但對象本身不存放在棧中,而是存放在堆(new 出來的對象)或者常量池中(字符串常量對象存放在常量池中)。
- 堆(heap):存放所有new出來的對象,在運行期創建。
- 常量池(constant pool):在堆中分配出來的一塊存儲區域,存放儲顯式的String常量和基本類型常量(float、int等)。另外,可以存儲不經常改變的東西(public static final),在編譯期就創建。常量池中的數據可以共享。
- 靜態存儲:存放靜態成員(static定義的)。
4.2、String str =“abc”
String a = "abc";
String b = "abc";
分析:第一行代碼執行後在常量池(constantpool)中創建了一個值爲abc的String對象,第二行執行時,因爲常量池中存在"abc"所以就不再創建新的String對象了。
4.3、String str =new String(“abc”)
String c = new String("xyz");
String d = new String("xyz");
分析:第一行中Class被加載時,"xyz"被作爲常量讀入,在常量池(constantpool)裏創建了一個共享的值爲"xyz"的String對象;然後當調用到new String("xyz")的時候,會在堆(heap)裏創建這個new String("xyz")對象;第二行執行時,由於常量池(constant pool)中存在"xyz"所以不再創建"xyz",然後創建新的new String("xyz")。
4.4、String str =“123” + new String(“abc”)
這行復制語句表示的是先在常量池(constantpool)裏創建了一個共享的值爲"xyz"的String對象(編譯期確定);new String(“abc”),不能在編譯期完成,需要在堆中創建對象,通過“+”操作生成一個新的字符串(在常量池中的值是“123abc”?),同時返回一個String類型變量引用。
String s0=”kvill”;
String s1=new String(”kvill”);
String s2=”kv” + new String(“ill”);
System.out.println( s0==s1 ); //false
System.out.println( s0==s2 ); //false
System.out.println( s1==s2 ); //false
- String.intern()應用
返回的是String變量值內容在常量池中值的引用。
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
System.out.println("s1 == s2");//true