这是否会导致varargs堆污染?

时间:2013-06-30 17:15:24

标签: java arrays generics variadic-functions

我收到了警告:

  

[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建议,但请记住,这门课程尚未完成。

3 个答案:

答案 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。如果您确定它已被处理,则可以安全地忽略或取消警告。