2014-01-25 24 views
11

我是新來的java.I仍然覺得我必須瞭解很多,所以如果這個問題似乎愚蠢的原諒我。 現在我正在通過http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html橋法如何工作?

在這裏,我發現了很多困惑。

public class Node<T> { 

    public T data; 

    public Node(T data) { 
     this.data = data; 
    } 

    public void setData(T data) { 
     System.out.println("Node.setData"); 
     this.data = data; 
    } 
} 


public class MyNode extends Node<Integer> { 
    public MyNode(Integer data) { 
     super(data); 
    } 

    public void setData(Integer data) { 
     System.out.println("MyNode.setData"); 
     super.setData(data); 
    } 

    public static void main(String[] args) { 
     MyNode mn = new MyNode(5); 
     Node n = mn; // A raw type - compiler throws an unchecked warning 
     n.setData("Hello"); // Causes a ClassCastException to be thrown. 
     Integer x = mn.data; 

    } 
} 

當我運行這段代碼我得到以下錯誤

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
at MyNode.setData(MyNode.java:1) 
at MyNode.main(MyNode.java:14) 

下面是混亂
1)爲什麼顯示如果通過他們說,博客閱讀1號線
2)類型擦除將取代以上代碼類型參數如下

public class Node { 

    private Object data; 

    public Node(Object data) { this.data = data; } 

    public void setData(Object data) { 
     System.out.println("Node.setData"); 
     this.data = data; 
    } 
} 

public class MyNode extends Node { 

    public MyNode(Integer data) { super(data); } 

    public void setData(Integer data) { 
     System.out.println(data); 
     super.setData(data); 
    } 

    public static void main(String[] args) { 
     MyNode mn = new MyNode(5); 
     Node n = mn;   // A raw type - compiler throws an unchecked warning 
     n.setData("Hello");  // Causes a ClassCastException to be thrown. 
     //Integer x = mn.data 

    } 
} 

whe n個I運行上面的代碼我沒有得到任何錯誤,代碼運行正常

從文檔中兩個R相同?爲什麼這種行爲上的不同對OOP

現在其他最重要的問題是,當我們繼承一個類,當我們調用超構造雖然超級對象沒有創建那麼什麼是使用調用超。請解釋。

回答

4

在第二個版本MyNode.setData不會覆蓋Node.setData,因爲它有不同的簽名。因此,在第二個示例中,不會發生動態調度,並調用Node.setData,這可以很好地處理字符串。

在第一個例子MyNode.setData並覆蓋Node.setData,所以它被調用,但它不能處理String S,它只能處理Integer這麼你得到ClassCastException

因此,如果該博客宣稱,這正是內部發生,這是錯誤的。他們可能的含義是:如果MyNode.setData仍然會在第二個示例中覆蓋Node.setData,則它可以像這樣工作。

5

從兩個R相同的文檔?爲什麼這種行爲不同

這兩個代碼示例之間存在不同行爲的原因是因爲當您用Object替換泛型T時,您間接導致setData()不再覆蓋超類中的setData() 。由於參數類型不同,因此在第二個示例中,您只是超載。所以在第二個例子中,你直接調用了超類,它帶有Object。在第一個例子中,你正在調用帶Integer的子類。

當我們調用超構造雖然不創建超級對象,然後有什麼用調用超級

超類和子類的是同一個對象(與兩者之間的代碼分裂類)。所以調用超類構造函數來初始化超類中定義的任何字段。在你的例子中,如果你從來沒有調用super(data),那麼this.data永遠不會被設置。

5

如果您通過博客閱讀他們說,類型擦除會取代類型參數將取代上面的代碼如下

是的,這是正確的。那就是當橋接方法開始生效。會發生什麼情況是,通過這種類型的擦除,子類中的setData()方法不再是超類setData()方法的重寫等效方法。所以,編譯時的行爲不會持續到運行時。爲了保持行爲,編譯器內部生成一個橋接方法

Bridge method is often generated by the compiler, when a type extends or implements a parameterized class or interface and type erasure changes the signature of any inherited method.

這裏是如何工作的。編譯器生成子類中的方法如下:

// Bridge method 
public void setData(Object data) { 
    setData((Integer) data); 
} 

現在,此方法將覆蓋超類的setData(Object)方法。正如您注意到的,此方法僅在內部調用原始方法,將data轉換爲Integer。這是你得到ClassCastException的地方。 data實際上是String類型,不能轉換爲Integer

當我運行上面的代碼我沒有得到任何錯誤,代碼運行正常

正如我前面所說,類型擦除後,在子類中setData()方法不會覆蓋一個超類的方法。所以,當你調用方法上Node參考,它會調用只有Node類的方法,它的簽名是:

public void setData(Object data) { 
    System.out.println("Node.setData"); 
    this.data = data; 
} 

而且不會有問題,這一點,因爲你沒有任何鑄造。您正在將String類型data存儲爲Object類型的引用。沒事兒。

當我們調用超級構造函數,雖然沒有創建超級對象,那麼調用super的用法是什麼。

那麼,這應該是一個單獨的問題。無論如何,重點是,一個對象的狀態包含在該類中聲明的數據成員,並且它是超級類。該特定類中的構造函數只會初始化該類中的狀態。要初始化超類中對象的狀態,必須鏈接super類構造函數。

進一步閱讀:

+0

那麼,如果你說的電橋法將增加,很抱歉,如果我理解力完全地你的answere – sumedha

+0

@sumedha是爲什麼第一個例子失敗,橋接方法被添加。這並不是真的導致您在'main'中調用方法失敗。這完全是內部的。問題是,你正在向該方法傳遞一個String類型的參數(這正是一個橋接方法),然後在內部嘗試將該參數強制轉換爲一個'Integer'類型,這是失敗的地方。 –

+0

如果第二個示例具有橋接方法的副本,那麼爲什麼它在第二個示例中失敗,請exaplain – sumedha