如何检查generics类型是否在java中实现了特定类型的generics接口?
可能重复:
运行时的局部变量的通用类型
我是Javagenerics的新手,来自.NET世界,我习惯于能够编写这样的方法:
public void genericMethod(T genericObject) { if (genericObject is IList) { //Do something... } }
该方法接受generics类型的对象,并检查该对象是否实现了通用接口IList
的特定版本,在本例中为IList
。
现在,在Java中,我能够做到这一点:
public void genericMethod(T genericObject) { if (genericObject instanceof Set) { //Do something... } }
但
Java不允许我这样做if (genericObject instanceof Set)
据我所知,由于类型擦除,通常在Java中,这将由类对象处理,我们将执行以下操作:
public void genericMethod(T genericObject) { Class testClass = OurTestingType.class; if (genericObject.getClass() == testClass) { //Do something... } }
但由于我正在检查的类型是通用接口,你不能这样做:
Class<Set> testClass = Set.class
那么,在Java中,我如何检查通用对象是否实现了特定类型的Set
?
Java实现了擦除,所以没有办法告诉运行时genericObject
是否是Set
的实例。 保证这一点的唯一方法是在generics上使用边界,或检查集合中的所有元素。
编译时通用边界
使用边界检查,将在编译时检查:
public void genericMethod(Set extends T> tSet) { // Do something with tSet here }
Java 8
我们可以在Java 8中使用流本地在一行中执行此操作:
public void genericMethod(T t) { if (t instanceof Set>) { Set> set = (Set>) t; if (set.stream().allMatch(String.class:isInstance)) { Set strs = (Set ) set; // Do something with strs here } } }
Java 7及更早版本
对于Java 7及更早版本,我们需要使用迭代和类型检查:
public void genericMethod(T t) { Set strs = new HashSet (); 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. } }
番石榴
根据Mark Peters在下面的评论,如果你可以将它添加到你的项目中,Guava也有为你做这个的方法:
public void genericMethod(T t) { if (t instanceof Set>) { Set> set = (Set>) t; if (Iterables.all(set, Predicates.instanceOf(String.class))) { Set strs = (Set ) set; // Do something with strs here } } }
声明Iterables.all(set, Predicates.instanceOf(String.class))
与set instanceof Set
基本相同。
遗憾的是,你没有Java中的那个选项。 在Java中, List
和List
之间没有运行时差异。 编译器确保您永远不会add()
Integer
add()
到List
。 即使编译器执行也不严格,所以你可以“合法地”使用未经检查的强制转换来做这样的可憎行为….
总而言之,对于(几乎)运行时类型识别的任何问题,您必须将List
用于实际内容:只是一个原始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 strings = (List ) genericObject; } }
一个有趣的观察:如果list
为空,则该方法对所有给定类型返回true。 实际上,空List
和空List
之间没有运行时差异。