java面試之Clone方法相等性判斷

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,這個objecthashcode是永遠不同的,這樣的話可能會影響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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章