2013-06-30 17 views
7

sto ottenendo l'avvertimento:Ciò causa inquinamento di heap con vararg?

[incontrollato] possibile inquinamento mucchio di tipo parametrico vararg Classe

Ma io sono sicuro se sarà effettivamente inquina:

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

Ecco l'implementazione completa se necessario:

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

Sono pronto per i suggerimenti OT per migliorare anche questo, ma tieni presente che questa classe non è terminata.

risposta

7

L'avviso sui vararg generici è correlato allo dangers of generic arrays. In teoria il metodo potrebbe abusare matrice di covarianza con il passato in serie causare inquinamento mucchio, per esempio:

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

ma va bene fintanto che l'implementazione del metodo non fa nulla stupido del genere. Alcune precauzioni di base sarebbero:

  • Non eseguire alcuna assegnazione a eventTypes.
  • Non restituire o esporre altrimenti eventTypes all'esterno del metodo.

con Java 7, si potrebbe annotare il metodo con @SafeVarargs, che promette in sostanza il compilatore che gli array generici sono a posto (il che significa che non è più sul chiamante per eliminare l'avviso).

+1

L'esempio basato sul mio codice ha chiarito quali sono le insidie. Le precauzioni suggerite mi aiutano a prevenire gli errori e quell'annotazione pulisce l'IDE. Tutto ciò con link utili. Risposta grande, compatta, grazie. – zsawyer

0

È necessario fare attenzione che il corpo del metodo di registrazione non elimini ClassCastException in fase di esecuzione a causa di argomenti non validi. Se si è sicuri che sia gestito, si può tranquillamente ignorare o sopprimere l'avviso.

+0

-1: Questo non ha nulla a che fare con gli argomenti che vengono passati, ma con il modo in cui il metodo tratta il suo parametro varargs. –

2

Ogni volta che si dispone di vararg generati (ad esempio, un elenco generico) si ha la possibilità di inquinamento heap. Per esempio:

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

Nel tuo esempio, hai Class<? extends Event> eventTypes... che cade in preda allo stesso problema:

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

    ... 
    ... 
} 

Java è solo che avvisa che c'è un potenziale soluzione di heap-inquinamento. In Java 7, gli avvertimenti sono generati anche nella dichiarazione del metodo, mentre nelle versioni precedenti era solo nei siti di chiamata.

Se si è certi che l'inquinamento da cumulo non può verificarsi, è possibile sopprimere l'avviso utilizzando l'annotazione @SafeVarargs.