2013-06-30 26 views
7

Tôi nhận được cảnh báo:Điều này có gây ra ô nhiễm heap với varargs?

[kiểm soát] có thể ô nhiễm đống từ tham số vararg loại Lớp

Nhưng tôi không chắc chắn nếu nó thực sự sẽ gây ô nhiễm:

public void register(EventListener listener, Class<? extends Event>... eventTypes) {} 

Đây là việc triển khai đầy đủ nếu cần thiết:

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); 
      } 
     } 
    } 
} 

Tôi đồng ý với các đề xuất OT để cải thiện điều này, nhưng hãy nhớ rằng lớp học này chưa hoàn thành.

Trả lời

7

Cảnh báo về các biến thể chung có liên quan đến dangers of generic arrays. Về mặt lý thuyết phương pháp này có thể lạm dụng mảng hiệp phương sai với thông qua trong mảng gây ô nhiễm đống, ví dụ:

Class<?>[] eventTypesWithWidenedType = eventTypes; 
eventTypesWithWidenedType[0] = String.class; 
Class<? extends Event> eventType = eventTypes[0]; // liar! 

Nhưng đó là tốt miễn là việc thực hiện phương pháp không làm bất cứ điều gì ngớ ngẩn như thế. Một số biện pháp phòng ngừa cơ bản sẽ là:

  • Không thực hiện bất kỳ chuyển nhượng nào đến eventTypes.
  • Không trả lại hoặc cách khác phơi bày eventTypes ngoài phương pháp.

Với Java 7, bạn có thể chú thích phương thức với @SafeVarargs, về cơ bản hứa với trình biên dịch rằng các mảng chung là không sao (nghĩa là nó không còn trên người gọi để chặn cảnh báo).

+1

Ví dụ dựa trên mã của tôi đã nêu rõ những cạm bẫy là gì. Các biện pháp phòng ngừa được đề xuất giúp tôi ngăn chặn những sai lầm và chú thích đó làm sạch IDE. Tất cả điều đó với các liên kết hữu ích. Câu trả lời tuyệt vời, nhỏ gọn, cảm ơn. – zsawyer

0

Bạn cần lưu ý rằng nội dung của phương thức đăng ký không ném ClassCastException vào thời gian chạy do các đối số bất hợp pháp. Nếu bạn chắc chắn rằng nó được xử lý hơn bạn một cách an toàn có thể bỏ qua hoặc ngăn chặn các cảnh báo.

+0

-1: Điều này không liên quan gì đến các đối số được truyền vào, nhưng với cách phương thức xử lý tham số varargs của nó. –

2

Bất cứ khi nào bạn có varargs được genericized (ví dụ, một danh sách genericized) bạn có một khả năng ô nhiễm đống. Ví dụ:

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! 
} 

Trong ví dụ của bạn, bạn có Class<? extends Event> eventTypes... rơi con mồi để cùng một vấn đề:

public static void register(EventListener listener, Class<? extends Event>... eventTypes) { 
    Object[] objectArray = eventTypes; 
    objectArray[0] = String.class; //Heap pollution 

    ... 
    ... 
} 

Java chỉ là cảnh báo bạn rằng có một giải pháp đống ô nhiễm tiềm năng. Trong Java 7, các cảnh báo được tạo ra tại khai báo của phương thức cũng như trong các phiên bản trước nó chỉ ở các trang gọi.

Nếu bạn chắc chắn rằng ô nhiễm đống không thể xảy ra, bạn có thể chặn cảnh báo bằng cách sử dụng chú thích @SafeVarargs.

Các vấn đề liên quan