1

私は現在、単純なイベントリスナーライブラリを作成しています。
これがリスナーのための私のインターフェースです:

public interface Listener<T> {
    // Event is a very simple type which holds a variable T data.
    public boolean run(Event<T> e);
}

私のクラスListenableはすべてListenerのをHashMapに記録します:

protected HashMap<String, ArrayList<Listener<?>>> listeners;

Listenableインスタンスに複数のイベントタイプを持たせたいので、ここではワイルドカードを使用しています。

問題のある部分は私のListenable::dispatchEvent()方法にあります:

public boolean dispatchEvent(Event<?> evt) {
        ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
        if (evtListeners == null) {
            return true;
        }

        for (Listener<?> lst : evtListeners) {
        //           vvv--- error
            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
        }


        return true;
}

エラーメッセージは次のとおりです。

タイプListenerのメソッドrun(Event)は、引数(Event)には適用できません。

私は「解決策」を見つけました(コンパイラにエラーを隠すという意味で):

for (Listener lst : evtListeners) {
            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
}

この場合、コンパイラは2つの警告しか生成しませんが、この手法は非常に貧弱であることをここで読みました。


私はそれをこのコードで動作させました

public <T> boolean dispatchEvent(Event<T> evt) {
        ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
        if (evtListeners == null) {
            return true;
        }

        for (int i = 0; i < evtListeners.size(); i++) {
            @SuppressWarnings("unchecked")
            Listener<T> lst = (Listener<T>) evtListeners.get(i);

            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
        }

        return true;
}

しかし、これがクリーンなコードだとは思えませんね。私のライブラリのユーザーは、同じイベントタイプ(evt.getType())のタイプを混在させないことを前提としています。

何か提案をいただければ幸いです。

4

1 に答える 1

2

メソッドのシグネチャを次のように変更する必要があります

public <T> boolean dispatchEvent(Event<T> evt)

タイプとして使用Tします:

for (Listener<T> lst : (ArrayList<Listener<T>>) evtListeners) {

これは通常「チェックされていない会話」の警告を与えることに注意してください@SuppressWarnings("unchecked")。iircでそれを無効にすることができます。

編集:チェックされていない会話の警告を取り除くのは難しいです。それらは単に、コンパイラがそのキャストを強制できないことを意味します。次のステートメントは正しく、役に立たず、後でコードを爆破します。

ArrayList<Thread> al1 = new ArrayList<Thread>();
al1.add(new Thread());
ArrayList<Exception> al2 = (ArrayList<Exception>) al1;

Javaのジェネリックは、多かれ少なかれ、キャストを節約し、型の安全性を高めるコンパイル時のヒントにすぎません。

于 2013-03-26T13:47:03.967 に答える