2014-07-09 34 views
0

本示例摘自Thinking in Java。泛型:如何使編譯器控制我將哪些類型放入構造函數

public class Automobile { 
} 

public class Holder<T> { 
    private T a; 
    public Holder(T a){ 
     this.a = a; 
    } 
    public void set(T a){ 
     this.a = a; 
    } 

    public T get(){ 
     return a; 
    } 

    public static void main(String[] args){ 
     Holder<Automobile> h = new Holder<Automobile>(new Automobile()); 
     Automobile a = (Automobile)h.get(); 
    } 
} 

然後進行解釋:您必須使用與main()中相同的尖括號語法來指定要放入其中的類型。

嗯,我什麼都不懂。我會理解,在違反此規則的情況下,必須將其視爲可能的編譯時錯誤。

但這個工程:

Holder<Automobile> h = new Holder(new Automobile()); 
    Automobile a = h.get(); 

而且這個工程:

Holder h = new Holder(new Automobile()); 
Automobile a = (Automobile)h.get(); 

所以,我可以看到,編譯器將無法控制我放進Holder對象。那麼,我根本就沒有注意到泛型。我有兩個問題:

  1. 使用它們的原因是什麼?只有在將物體鑄造回汽車時節省我一些努力?

  2. 有什麼辦法讓編譯器控制我,讓我真的把汽車放入持有人嗎?

+1

看看原始類型。 –

+0

我添加了兩條評論,java 1.7,並修復了第三個代碼片段中的錯誤,請在編輯 – EpicPandaForce

回答

1

在這裏鑄造是不必要的:

Holder<Automobile> h = new Holder<Automobile>(new Automobile()); 
    Automobile a = (Automobile)h.get(); 

但這裏是必要的:

Holder h = new Holder(new Automobile()); 
Automobile a = (Automobile)h.get(); 

這是做事情由於Java 1.5及以上有史以來的最好辦法:

Holder<Automobile> h = new Holder<Automobile>(new Automobile()); //specify the generic parameter on both static and dynamic type 
Automobile a = h.get(); //no casting is necessary 

或者上面的Java 1.7簡單:

Holder<Automobile> h = new Holder<>(new Automobile()); //diamond operator so you don't need to respecify the same thing 
Automobile a = h.get(); 



爲什麼以這種方式使用泛型是有用的原因是,你不能做到以下幾點:

Integer a = new Integer(6); 
List list = new ArrayList(); 
list.add(a); 
list.add("5"); 
for(int i = 0; i < list.size(); i++) 
{ 
    Integer integer = (Integer)list.get(i); //crashes at "5" which is String at runtime 
    System.out.println(integer); 
} 

正如你可以看到,如果你可以把對象的任何子類進入榜單沒有界限,然後你需要明確的轉換,如果你把任何不是你期望的東西放到列表中,那麼它會崩潰。請注意,如果沒有泛型,您也不會知道您期望將哪種類型放入列表中,這意味着您需要跟蹤列表應該包含的內容,當您嘗試執行時,這非常糟糕邏輯如下所示:Java generics and casting to a primitive type

而且我甚至不知道這是可能沒有泛型:Is it possible to cast Map<Field, Value> to Map<Mirror, Mirror> when it is known that Field and Value extend Mirror?

因此從技術上仿製藥使額外的功能,同時還鼓勵類型安全,因此錯誤更少的代碼,這始終是不錯。

Integer a = new Integer(6); 
List<Integer> list = new ArrayList<Integer>(); 
list.add(a); 
list.add("5"); //this will not compile -> you won't need to wait until runtime to see that things are incorrect! 
+1

後檢查答案。「這是從Java 1.5及更高版本開始的最佳做法:」我不同意。您正在使用原始類型的構造函數,這是不安全的。正確的方法是'持有人 h =新持有人(新汽車());'或(在Java 1.7+)'持有人 h =新持有人<>(新汽車());'。使用原始類型構造函數關閉泛型類型檢查。假設'Holder '的構造函數是'public Holder(List a)',then'Holder h = new Holder(new ArrayList ());'即使顯然是錯誤的,也是允許的。 – newacct

+0

@newacct絕對正確!對不起,錯誤,顯然構造參數搞砸了我。固定。這不應該是一種原始類型。 – EpicPandaForce

0

泛型的要點是編寫可以包含任何對象或可以與任何對象一起工作的數據結構。您在使用時,其類型的對象它應該包含,例如指定:

ArrayList<String> stringList = new ArrayList<String>(); 

(Diamondoperator作秀不是寫在短)

回答的問題: 1:編寫代碼能工作與所有對象(如集合),是的,編譯器理解,並可以在編譯時鍵入檢查您的代碼 2:是的,不使用泛型,而是寫你的汽車的代碼spezific

相關問題