Eri*_*son 22 java generics collections
可能重复:
运行时局部变量的通用类型
我是Java泛型的新手,来自.NET世界,我习惯于能够编写这样的方法:
public void genericMethod<T>(T genericObject)
{
if (genericObject is IList<String>)
{
//Do something...
}
}
Run Code Online (Sandbox Code Playgroud)
该方法接受泛型类型的对象,并检查该对象是否实现了通用接口的特定版本IList<>
,在本例中IList<String>
.
现在,在Java中,我能够做到这一点:
public <T> void genericMethod(T genericObject)
{
if (genericObject instanceof Set<?>)
{
//Do something...
}
}
Run Code Online (Sandbox Code Playgroud)
但
Java并没有让我做if (genericObject instanceof Set<String>)
据我所知,由于类型擦除,通常在Java中,这将由类对象处理,我们将执行以下操作:
public <T> void genericMethod(T genericObject)
{
Class<OurTestingType> testClass = OurTestingType.class;
if (genericObject.getClass() == testClass)
{
//Do something...
}
}
Run Code Online (Sandbox Code Playgroud)
但由于我正在检查的类型是通用接口,你不能这样做:
Class<Set<String>> testClass = Set<String>.class
那么,在Java中,我如何检查通用对象是否实现了特定类型Set<String>
?
Bri*_*ian 20
Java实现了擦除,因此没有办法告诉运行时是否genericObject
是实例Set<String>
.保证这一点的唯一方法是在泛型上使用边界,或检查集合中的所有元素.
使用边界检查,将在编译时检查:
public <T extends SomeInterface> void genericMethod(Set<? extends T> tSet) {
// Do something with tSet here
}
Run Code Online (Sandbox Code Playgroud)
我们可以在Java 8中使用流本地在一行中执行此操作:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (set.stream().allMatch(String.class:isInstance)) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
Run Code Online (Sandbox Code Playgroud)
对于Java 7及更早版本,我们需要使用迭代和类型检查:
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.
}
}
Run Code Online (Sandbox Code Playgroud)
根据Mark Peters在下面的评论,如果你可以将它添加到你的项目中,Guava也有为你做这个的方法:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
声明Iterables.all(set, Predicates.instanceOf(String.class))
基本上与之相同set instanceof Set<String>
.
遗憾的是,你没有Java中的那个选项.在Java中,a 和a 之间没有运行时差异.这是编译器永远不会确保您的到.即使编译器执行也不严格,所以你可以"合法地"使用未经检查的演员表来做这样的可憎行为......List<String>
List<Integer>
add()
Integer
List<String>
总而言之,对于(几乎)任何运行时类型识别的问题,你必须考虑List<String>
它实际上是什么:只是原始的List
.这称为类型擦除.
也就是说,没有什么能阻止你检查List
其类型的内容:
public boolean isListOf(List<?> list, Class<?> c) {
for (Object o : list) {
if (!c.isInstance(o)) return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
要使用此方法:
// ...
if (genericObject instanceof List<?>) {
if (isListOf((List<?>) genericObject, String.class)) {
@SuppressWarnings("unchecked")
List<String> strings = (List<String>) genericObject;
}
}
Run Code Online (Sandbox Code Playgroud)
一个有趣的观察:如果list
为空,则该方法对所有给定类型返回true.其实,有一个空之间没有区别运行时List<String>
和一个空的List<Integer>
任何.