2012-09-20 67 views
12

可能重複:
Generic type of local variable at runtime如何檢查通用類型是否在java中實現了特定類型的通用接口?

我是新來的Java泛型,並從.NET世界的未來,我已經習慣了能夠寫一個方法是這樣的:

public void genericMethod<T>(T genericObject) 
{ 
    if (genericObject is IList<String>) 
    { 
     //Do something... 
    }    
} 

該方法接受一個通用類型的對象,並檢查對象是否實現一個特定版本的通用接口IList<>,在這種情況下,IList<String>

現在,在Java中,我能夠做到這一點:

public <T> void genericMethod(T genericObject) 
{ 
    if (genericObject instanceof Set<?>) 
    { 
     //Do something... 
    } 
} 

Java那樣讓我做if (genericObject instanceof Set<String>)

據我所知,是因爲類型擦除,通常在Java中,這將由類對象處理,並且我們將執行如下操作:

public <T> void genericMethod(T genericObject) 
{ 
    Class<OurTestingType> testClass = OurTestingType.class; 
    if (genericObject.getClass() == testClass) 
    { 
     //Do something... 
    } 
} 

,但因爲我檢查的類型是一個通用的接口,你可以這樣做:

Class<Set<String>> testClass = Set<String>.class

那麼,如何在Java中,我做檢查,如果通用對象實現Set<String>的具體類型?

+0

泛型是一個編譯時功能,因此您不能簡單地獲取運行時使用的特定泛型類型。你可以從內容或附加的參數中推斷出它。 '類 t類' –

回答

13

Java實現了擦除,因此如果genericObjectSet<String>的實例,則無法告訴運行時間。確保這一點的唯一方法是使用泛型的邊界,或者檢查集合中的所有元素。

使用邊界檢查:

public <T extends SomeInterface> void genericMethod(Set<? extends T> tSet) { 
    // Do something with tSet here 
} 

隨着迭代和類型檢查:

public <T> void genericMethod(T t) { 
    Set<String> strs = new HashSet<String>(); 
    Set<?> tAsSet; 
    if (t instanceof Set<?>) { 
     tAsSet = (Set<?>) t; 
     for (Object obj : tAsSet) { 
      if (obj instanceof String) { 
       strs.add((String) obj); 
      } 
     } 
     // Do something with strs here 
    } else { 
     // Throw an exception or log a warning or something. 
    } 
} 

編輯:按照下面馬克彼得斯的評論作爲,番石榴也有適合你,如果做到這一點的方法您可以將其添加到您的項目中:

public <T> void genericMethod(T t) { 
    if (t instanceof Set<?>) { 
     Set<?> set = (Set<?>) t; 
     if (Iterables.all(set, Predicates.instanceOf(String.class))) { 
      Set<String> strs = (Set<String>) set; 
      // Do something with strs here 
     } 
    } 
} 

聲明Iterables.all(set, Predicates.instanceOf(String.class))set instanceof Set<String>基本相同。

+3

在Guava中,您可以使用'Iterables.all(tAsSet,Predicates.instanceOf(String.class))'來檢查'Iterable'是否僅包含字符串。或者使用'Iterables.filter(tAsSet,String.class)'過濾。 –

+0

@MarkPeters番石榴總是有這樣的整潔的小方法,很好找。 – Brian

+0

有沒有實例的方法會很方便...我的情況是一個函數'> funcname(T obj)',我想對K類型做一些檢查。 – Nyerguds

8

不幸的是,您在Java中沒有這個選項。在Java中,List<String>List<Integer>之間沒有運行時間。它是編譯器,它確保您永遠不會add()IntegerList<String>。即使這種編譯器的執法並不嚴格,所以你可以「合法地」執行這種可恥的強制執行......總之,對於(幾乎)運行時類型識別的任何問題,您必須採取List<String>的實際內容:僅僅是一個原始的List。這就是所謂的類型擦除

這就是說,沒有什麼能阻止你從檢查一個List的內容,爲他們的類型:

public boolean isListOf(List<?> list, Class<?> c) { 
    for (Object o : list) { 
     if (!c.isInstance(o)) return false; 
    } 

    return true; 
} 

要使用此方法:

// ... 
    if (genericObject instanceof List<?>) { 
     if (isListOf((List<?>) genericObject, String.class)) { 
      @SuppressWarnings("unchecked") 
      List<String> strings = (List<String>) genericObject; 
     } 
    } 

一個有趣的現象:如果list是空的,該方法對所有給定的類型返回true。實際上,在空的List<String>和空的List<Integer>之間沒有運行時差異。

相關問題