这是我的代码:
Set<Class<Event>> s = new HashSet<>();
Set<Class<? extends Event>> s2 = new HashSet<>();
Event e = new Event();
s.add(e.getClass()); // #1
s2.add(e.getClass()); // #2
class Event {
// ...
}
为什么编译器会在语句#1
上引发错误?
我正在使用Java 7.
答案 0 :(得分:9)
如果您查看documentation of getClass()
method,您会看到
实际结果类型为
Class<? extends |X|>
,其中| X |是调用getClass的表达式的静态类型的擦除。例如,此代码片段中不需要强制转换:Number n = 0; Class<? extends Number> c = n.getClass();
因此e.getClass()
的结果将是Class<? extends Event>
,这正是Set<Class<? extends Event>> s2
所要存储的内容。这就是为什么
s2.add(e.getClass()); // OK
工作正常。
但是在Set<Class<Event>> s
的情况下,情况略有不同。它只能存储Class<Event>
。允许它存储来自Class<? extends Event>
引用的对象在类型安全性方面非常危险。
请看一下这个示例(为了便于理解,我们可以将Class
替换为List
,我们的Action
个实例将Animal
类似Dog
和{ {1}})。
Cat
现在我们假设List<Dog> dogs = new ArrayList<>();
List<? extends Animal> generalList = dogs;
Set<List<Animal>> set = new HashSet<>();
可以存储Set<List<Animal>> set
List<? extends Animal>
现在我们能够做一些可怕的事情
set.add(generalList);
还记得我们的for (List<Animal> animalList : set){
animalList.add(new Cat()); // I just placed Cat in container full of Dogs!
}
列表吗?现在它包含List<Dog> dogs = new ArrayList<>();
所以如果我这样做:
Cat
我可能会看到类似于
的内容WOF
纬
汪
喵! (psst:让我离开这里!)
...
或代替for (Dog dog : dogs){
dog.speak();
}
某些例外,例如Meow!
或最有可能NoSuchMethodException
。
所以当你看到允许这种机制不是很明智。