2017-02-22 7 views
1

私は、さまざまなカスタムイベントとリスナーに反応する必要のあるプログラムを開発中です。Javaの汎用addListener

私はジェネリック薬を使用してそれを短くしようとしています、実際には、私は間違いがどこにあるのか分かりません。

ここに私のコード:

リスナーとイベント:

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の無効なクラスリテラル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'はどのように見えますか(特にaddメソッドとremoveメソッド)? – Calculator

+2

@ Calculatorおそらく[javax.swing.event.EventListenerList](http://docs.oracle.com/javase/8/docs/api/javax/swing/event/EventListenerList.html)のように見えます。 – VGR

答えて

2

通常、あなただけのすべてのリスナーのタイプのための2つのメソッドを宣言します実行時の型によって追加/削除されます。

たとえば、サポートされるリスナータイプのリストを作成します。 2種類MyFirstListener.classMySecondListener.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; 
} 

、あなたが使用することができますあなたのaddListenerremoveListenerメソッド内この方法:

@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

アン同じ結果を持っているもう一つの方法は、この実装が、それほど一般的なではありません: ' 公共空のaddListener(Tリスナー){ \t場合MyFirstListenerのinstanceof(リスナー){ \t \t listenerList.add(MyFirstListener.class、(MyFirstListener)リスナー); \t} else if(listener instanceof MySecondListener){ \t \t listenerList.add(MySecondListener.class、(MySecondListener)listener); \t}他{ \t \t System.err.println( "間違ったリスナー")。 \t} } ' – MonkeyJLuffy

0

このようにクラスを参照することはできません。代わりにlistener.getClassを呼び出します。あなたが動的にリスナーを追加および削除できるようにしたい場合は、あなたがする必要があり、リスナーの種類を検索する必要があります

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

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

+0

はgetClass()は 'MyFirstListener.class'もどちらが返されます。私のFirstClass.classまたはSecondClass.classを与えることではなくので、しかし、それは、動作しません。 'MySecondListener.class'。 – VGR