2012-09-20 43 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>之间没有运行时差异。

相关问题