我收到了警告:
[unchecked]参数化vararg类型Class
可能造成的堆污染
但我不确定它是否真的会污染:
public void register(EventListener listener, Class<? extends Event>... eventTypes) {}
如果有必要,这是完整的实施:
public class EventDispatcher {
public static ConcurrentLinkedQueue<Event> eventQueue;
public static ConcurrentHashMap<Class<? extends Event>, CopyOnWriteArrayList<EventListener>> eventsListenerMap =
new ConcurrentHashMap<>();
public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
for (Class<? extends Event> eventType : eventTypes) {
if (eventsListenerMap.containsKey(eventType)) {
eventsListenerMap.get(eventType).addIfAbsent(listener);
} else {
CopyOnWriteArrayList<EventListener> initializingListeners =
new CopyOnWriteArrayList<>();
initializingListeners.add(listener);
eventsListenerMap.put(eventType, initializingListeners);
}
}
}
}
我全力以赴提出改进建议的OT建议,但请记住,这门课程尚未完成。
答案 0 :(得分:8)
关于通用变量的警告与dangers of generic arrays有关。从理论上讲,该方法可能会滥用数组协方差与传入的数组导致堆污染,例如:
Class<?>[] eventTypesWithWidenedType = eventTypes;
eventTypesWithWidenedType[0] = String.class;
Class<? extends Event> eventType = eventTypes[0]; // liar!
但只要方法实现不做那样愚蠢的事情就没关系。一些基本的预防措施是:
eventTypes
进行任何分配。eventTypes
。使用Java 7,您可以使用@SafeVarargs注释该方法,它基本上向编译器承诺通用数组是可以的(意味着调用者不再禁止警告)。
答案 1 :(得分:2)
每当你拥有通用化的varargs(例如,通用化列表)时,你就有可能出现堆污染。例如:
public void doSomethingWithStrings(List<String>... strings) {
Object[] objectArray = strings; //Valid because Object is a valid supertype
objectArray[0] = Arrays.asList(new Integer(42)); //Heap pollution
String string = strings[0].get(0); //Oops! ClassCastException!
}
在您的示例中,您Class<? extends Event> eventTypes...
会成为同一问题的牺牲品:
public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
Object[] objectArray = eventTypes;
objectArray[0] = String.class; //Heap pollution
...
...
}
Java只是警告您存在潜在的堆污染解决方案。在Java 7中,警告也是在方法声明时生成的,而在以前的版本中,它只在调用站点生成。
如果您确定不会发生堆污染,可以使用@SafeVarargs
注释来禁止警告。
答案 2 :(得分:0)
您需要注意,由于非法参数,register方法的主体不会在运行时抛出ClassCastException。如果您确定它已被处理,则可以安全地忽略或取消警告。