2015-01-07 6 views
2

Мне нужно реализовать шаблон Observer со списком слушателей в классе событий.EventSource с картой <Класс <? extends Event>, List <EventListener <? extends Event >> without unchecked call

у меня есть:

пустой интерфейс Event

public interface Event {} 

интерфейс для Слушателей:

public interface EventListener<T extends Event> { 
void handle(T event); 

Class<T> getEventClass();} 

и события источник:

public class EventSource { 
private final Map<Class<? extends Event>, List<EventListener<? extends Event>>> listeners = new HashMap<>(); 

public <T> void subscribe(EventListener<? extends Event> listener) { 
    Class<? extends Event> eventClass = listener.getEventClass(); 
    if (!listeners.containsKey(eventClass)) { 
     listeners.put(eventClass, new ArrayList<>()); 
    } 
    listeners.get(eventClass).add(listener); 
} 

public void unsubscribe(EventListener listener) { 
    listeners.remove(listener.getEventClass()); 
} 

public void fire(Event event) { 
    for (EventListener listener : listeners.get(event.getClass())) { 
     listener.handle(event); //<-- Unchecked call to 'handle(T)' as a member of raw type... 
    } 
}} 

Он работает, но у меня есть " Непроверенный вызов " предупреждение. Как этого избежать?

Я пробовал:

public void fire(Event event) { 
    for (EventListener<? extends Event> listener : listeners.get(event.getClass())) { 
     listener.handle(event);//<-- compilation error 
    } 
} 

, но в этом случае у меня есть «ручка не может быть применен к ...» ошибка компиляции.

Заранее благодарен!

+0

Использование NetBeans 7.4 Я не получаю свою ошибку, но я получаю: 'несовместимые типы: ArrayList не могут быть преобразованы для списка > 'под вашим' listeners.put (eventClass, новый ArrayList <>()); ' – gtgaxiola

+0

Спасибо за советы. Я понимаю проблему. В Map , List >> компилятор не знает, что "?" в классе и "?" в списке - один и тот же тип. И я не вижу способа передать это компилятору. – Vitaly

ответ

1

«бесконтрольно вызов» предупреждение было сообщено по уважительной причине - вы использовали необработанную форму EventListener. Когда вы указали параметр типа ? extends Event, он дал ошибку компиляции, потому что компилятор не имеет то, что Event обрабатывает EventListener - он знает только, что это особый тип Event. Аналогично, он не знает тип времени выполнения event - это может быть любой конкретный тип Event.

Тип должен быть известен тем, что имеет смысл. Я бы сделал EventSource generic, указав тип Event с параметром ограниченного типового типа.

class EventSource<E extends Event> { 

Многие ? extends Event заявления изменится использовать E, например,

private final Map<Class<? extends Event>, List<EventListener<E>>> listeners = new HashMap<>(); 

Есть много других заявлений, которые изменят использовать E.

Теперь fire примет E так, что он может быть передан в handle:

public void fire(E event) { 
    for (EventListener<E> listener : listeners.get(event.getClass())) { 
     listener.handle(event); // Now this compiles 
    } 
} 
+0

Спасибо, но я не могу просто изменить to В этом случае я не могу позвонить subscribe() для подклассов EventListener. – Vitaly

0

Изменить

listeners.put(eventClass, new ArrayList<>());    

в

listeners.put(eventClass, new ArrayList<EventListener<? extends Event>>());   

Я считаю, что сделает интерфейс метод handle ведут себя, как предполагается

+0

Спасибо, но ничего не меняет. В Java 7 <> (diamond) - автоматическая подстановка EventListener Vitaly

+0

@VitalyChibrikov Я использую Java 7, а оператор <> алмаза не определен на LHS-операторе, так как вы просто создаете ArrayList с вашим вызовом 'put'. Поэтому вы должны явно установить его, иначе компилятор будет просто указывать: gtgaxiola

+0

Да, вы правы. listeners.put (eventClass, новый ArrayList <>()); 1,8 уровня проекта, а не 1,7. В Java 7 мне нужна полная версия общей инициализации, как вы упомянули. – Vitaly

Смежные вопросы