2017-02-22 13 views
1

Я работаю над программой, которая должна реагировать на различные пользовательские события и прослушиватели.Generic addListener в Java

Я пытаюсь сделать его коротким с помощью дженериков, факт в том, что я не понимаю, где моя ошибка.

Вот мой код:

слушателей и событие:

public interface MyFirstListener extends EventListener { 
    void firstRequest(String text); 
} 

public interface MySecondListener extends EventListener { 
    void secondRequest(String text); 
} 

public class MyEvent extends EventObject { 
    private String text = null; 

    public MyEvent(Object source, String text) { 
     super(source); 
     this.text = text; 
    } 

    public String getText() { 
     return text; 
    } 
} 

А вот хитрый код:

public class MyProblem { 

    private EventListenerList listenerList = new EventListenerList(); 

    public MyProblem() {} 

    public <T extends EventListener> void addListener(T listener) { 
     listenerList.add(T.class, listener); // Here I have : Illegal class literal for the type parameter T 
    } 

    public <T extends EventListener> void removeListener(T listener) { 
     listenerList.remove(T.class, listener); // Here I have : Illegal class literal for the type parameter T 
    } 

    void fireFirstRequestEvent(MyEvent evt) { 
     for (MyFirstListener listener : listenerList.getListeners(MyFirstListener.class)) { 
      listener.firstRequest(evt.getText()); 
     } 
    } 

    void fireSecondRequestEvent(MyEvent evt) { 
     for (MySecondListener listener : listenerList.getListeners(MySecondListener.class)) { 
      listener.secondRequest(evt.getText()); 
     } 
    } 

    public static void main(String[] args) { 

     FirstClass first = new FirstClass(); 
     SecondClass second = new SecondClass(); 

     MyProblem problem = new MyProblem(); 
     problem.addListener(first); 
     problem.addListener(second); 
    } 
} 


class FirstClass implements MyFirstListener { 
    @Override 
    public void firstRequest(String text) { 
     // Do Something 
    } 
} 

class SecondClass implements MySecondListener { 
    @Override 
    public void secondRequest(String text) { 
     // Do Something 
    } 
} 

Проблема заключается в методах addListeners и removeListeners, у меня есть эта ошибка: Недопустимый литерал класса для параметра типа T Я не понимаю, как его поймать.

Я стараюсь также этот код:

listenerList.add(listener.getClass(), listener); // Here I have : The method add(Class<T>, T) in the type EventListenerList is not applicable for the arguments (Class<capture#1-of ? extends EventListener>, T) 

я попробовать другие вещи без результата, и я не нахожу решения, которые соответствуют мой код.

У кого-нибудь есть решение или оно неразрешимо? Моя цель - иметь более короткий код и даже красиво.

Спасибо-х

+2

[Тип стирания] (http://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens) предотвращает использование 'T.class' во время выполнения. –

+0

Как выглядит ваш 'EventListenerList' (особенно методы добавления и удаления)? – Calculator

+2

@Calculator Вероятно, это выглядит как [javax.swing.event.EventListenerList] (http://docs.oracle.com/javase/8/docs/api/javax/swing/event/EventListenerList.html). – VGR

ответ

2

Как правило, вы бы просто объявить для каждого типа слушателя два метода:

public void addFirstListener(MyFirstListener listener) { 
    listenerList.add(MyFirstListener.class, listener); 
} 

public void removeFirstListener(MyFirstListener listener) { 
    listenerList.remove(MyFirstListener.class, listener); 
} 

Если вы хотите, чтобы иметь возможность добавлять и удалять слушатель динамически, вам придется для поиска типа слушателя, который должен быть добавлен/удален по типу времени выполнения.

Например, создайте список поддерживаемых типов прослушивателей. В вашем примере для двух типов MyFirstListener.class и MySecondListener.class:

private final static List<Class<? extends EventListener>> SUPPORTED_LISTENER_TYPES 
     = Arrays.asList(MyFirstListener.class, MySecondListener.class); 

Тогда вам нужен метод, который способен для поиска соответствующего типа слушателя для данного слушателя:

private Class<? extends EventListener> getListenerType(EventListener listener){ 
    for(Class<? extends EventListener> listenerType : SUPPORTED_LISTENER_TYPES){ 
     if(listenerType.isAssignableFrom(listener.getClass())){ 
      return listenerType; 
     } 
    } 
    return null; 
} 

Теперь вы можете использовать этот метод внутри addListener и removeListener метода:

@SuppressWarnings("unchecked") 
public void addListener(EventListener listener) { 
    if(listener == null){ 
     return; 
    } 
    Class<? extends EventListener> listenerType = getListenerType(listener); 
    if(listenerType == null){ 
     throw new IllegalArgumentException("Listener " + listener + " not supported"); 
    } 
    listenerList.add((Class<EventListener>)getListenerType(listener), listener); 
} 

непроверенные литой здесь так как данный listener будет являться потомком типа, указанном getListenerType().

+0

Да, у вас есть права. После ваших ответов я пытаюсь использовать свой код с помощью решения @Dominik, но getClass() возвращает мне FirstClass.class или SecondClass.class, но не тип интерфейса (FirstListener .class и SecondListener.class). Затем я реализую обычный способ с addListeners для каждого вида. – MonkeyJLuffy

+0

Другим способом получить такой же результат является эта реализация, но не такая общая: ' public void addListener (T слушатель) { \t if (слушатель экземпляр MyFirstListener) { \t \t listenerList.add (MyFirstListener.class, (MyFirstListener) прослушиватель); \t} else if (listener instanceof MySecondListener) { \t \t listenerList.add (MySecondListener.class, (MySecondListener) прослушиватель); \t} else { \t \t System.err.println («Неправильный слушатель»); \t} } ' – MonkeyJLuffy

0

Вы не можете Приведи класс таким образом. Вместо этого вызовите listener.getClass.

+0

getClass() не вернет ни MyFirstListener.class, ни 'MySecondListener.class'. – VGR