2015-06-19 13 views
0

我前幾天正在編寫一個程序,要求我:獲取ArrayList<String>中特定對象的頻率,刪除接口未指定的給定項等的所有匹配項等。我決定寫我自己的幫手類,並希望儘可能地重複使用它。我決定將List指定爲集合的參數類型,所以我可以將它用於任何實現List接口的類。但是這些類通常使用泛型來定義,我不知道要刪除的項目是什麼類的類型。所以我要麼一般地定義靜態輔助方法,因爲靜態類不能顯式地包含泛型類型,要麼定義要刪除的對象的類類型爲Object。我用兩種方式實現了它,見下面,但我想知道是否有任何好處使用其中一個。在Java中使用泛型或對象類型爲靜態輔助類會更好嗎?

在話題的一些其他問題:

  1. 爲什麼我只能通過在方法頭,而不是類頭定義它來解決泛型類型的引用在靜態情況下?
  2. 當使用這種靜態方法時,爲什麼我不是必須在其用法中聲明Type類?即ListTools_V2.getFrequencyOf(ArrayList<String> items, String s)仍然有效。

實現使用對象類類型

import java.util.List; 

/** General utility class for performing frequently needed operations 
    on any class implementing the List interface **/ 
public class ListTools { 

    public static void removeAllOccurrences(List items, Object o) { 
     while(items.contains(o)) { 
      items.remove(o); 
     } 
    } 

    public static int getFrequencyOf(List items, Object o) { 
     int frequency = 0; 
     for(Object item : items) { 
      if(item.equals(o)) { 
       frequency++; 
      } 
     } 
     return frequency; 
    } 

} 

使用泛型實現

import java.util.List; 

/** General utility class for performing frequently needed operations 
    on any class implementing the List interface. This implementation 
    uses generics to maximize reusability. **/ 
public class ListTools_V2 { 

    public static <E> void removeAllOccurrences(List<E> items, E o) { 
     while(items.contains(o)) { 
      items.remove(o); 
     } 
    } 

    public static <E> int getFrequencyOf(List<E> items,E o) { 
     int frequency = 0; 
     for(E item : items) { 
      if(item.equals(o)) { 
       frequency++; 
      } 
     } 
     return frequency; 
    } 

} 
+0

[這](https://docs.oracle.com/javase/tutorial/java/generics/why:當沒有必要約束類型變量反對任何你應該用通配符參數吧。 html)和[this](https://docs.oracle.com/javase/tutorial/java/generics/methods.html)都很好。 – TNT

+0

夥計,我希望我不會毀掉你的一天:http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#frequency(java.util.Collection,%20java。 lang.Object) –

+0

@jangroth感謝您指出了這一個了,但我仍然很高興我實現了他們自己。在整個過程中肯定學習一些基本原則。 – bmcentee148

回答

0

一般是更好,因爲它檢測到在編譯時鍵入相關的問題。
在運行時發生「擦除」並且對泛型沒有「含義」。

例如:

List apples = new ArrayList(); 
apples.add(new Apple()); 
apples.add(new Mango()); //compiles, but this is wrong 
apples.add(new Chair()); //compiles, but this is wrong 



你當然必須知道各種通用機械的「陷阱」的。 例子我可以很容易地想到的是:
List<Mango>不擴展List<Fruit>,所以你應該使用List<? super Fruit>List<? extends Fruit>

你不能這樣做:

T.getClassName() 
+0

「編譯,但這是錯誤的」爲什麼它是「錯誤的」? – newacct

+0

正如你可能會遇到運行時問題,如果你要嘗試執行檢索對象的演員,例如 - 訪問蘋果的名單,試圖讓一個對象,將其轉換爲蘋果,並有ClassCastException異常被誤爲芒果添加。如果使用泛型,這些錯誤將在編譯時被阻止。 –

+0

這個問題沒有檢索。 – newacct

0

泛型是實現這些類的推薦方式。它們可以用來給你的用戶提供一些隱含的信息(使用這個類的人)。 例如:

List<Cat> cats = ...; 
ListTools.removeAllOccurrences(cats, new Dog()); 

這是因爲毫無意義,不能有貓的名單內的任何狗。但用戶可以執行此代碼,並想象他已從貓列表中刪除了一些狗。另一方面,通用版通知用戶有關此不恰當的呼叫。

List<Cat> cats = ...; 
ListTools_V2.removeAllOccurrences(cats, new Dog()); // Compile time error because it is pointless 

另外還有一個性能增益。如果貓列表中包含數千只貓,您是否真的想在大量貓列表中搜索該狗? (包含方法實際上搜索整個列表),或者你只是想避免在編譯時? ;)

+0

「這是毫無意義的,因爲貓列表裏面不能有任何狗。」不對。根據「Dog」和「Cat」的實現方式,「Dog」可以與「Cat」中的「.equals()」相同(如'.equals()'),並且它是平等的, – newacct

+0

雅你是對的。我一直沒有提供貓和狗的代碼,假設他們完全是兩個不同的類。 – Gobinath

0

您getFrequencyOf()方法體是在這兩種情況下,除了在一種情況下你逝去的原始名單,而在另一個你參數化它接受任何類型基本相同。

1-

public static int getFrequencyOf(List items, Object o) { 
     int frequency = 0; 
     for(Object item : items) { 
      if(item.equals(o)) { 
       frequency++; 
      } 
     } 
     return frequency; 
    } 

在這裏,您List是原始類型。對泛型類型列表的引用應該被參數化,而不是。但它是打開任何類型的列表(整型,長整型,字符串等)

2-

public static <E> int getFrequencyOf(List<E> items,E o) { 
     int frequency = 0; 
     for(E item : items) { 
      if(item.equals(o)) { 
       frequency++; 
      } 
     } 
     return frequency; 
    } 

在這裏,您列表不是一個原始類型。泛型類型List的引用應該被參數化,它是。這也適用於任何類型的列表(整數,長整型,字符串等)

1

這兩個操作在給定的對象引用和列表中的元素之間的等式(.equals())上操作,並且相等性不限於相同類型的對象,因此您不應將o限制爲與列表的類型參數相同的類型。

然而,原料類型是壞的,所以你不應該使用原始類型List

public static void removeAllOccurrences(List<?> items, Object o) 
public static int getFrequencyOf(List<?> items, Object o) 
相關問題