在Java中创建自定义事件


Answers:


421

您可能想研究观察者模式

以下是一些示例代码,可以帮助您入门:

import java.util.*;

// An interface to be implemented by everyone interested in "Hello" events
interface HelloListener {
    void someoneSaidHello();
}

// Someone who says "Hello"
class Initiater {
    private List<HelloListener> listeners = new ArrayList<HelloListener>();

    public void addListener(HelloListener toAdd) {
        listeners.add(toAdd);
    }

    public void sayHello() {
        System.out.println("Hello!!");

        // Notify everybody that may be interested.
        for (HelloListener hl : listeners)
            hl.someoneSaidHello();
    }
}

// Someone interested in "Hello" events
class Responder implements HelloListener {
    @Override
    public void someoneSaidHello() {
        System.out.println("Hello there...");
    }
}

class Test {
    public static void main(String[] args) {
        Initiater initiater = new Initiater();
        Responder responder = new Responder();

        initiater.addListener(responder);

        initiater.sayHello();  // Prints "Hello!!!" and "Hello there..."
    }
}

相关文章:Java:创建自定义事件


是否有正当的理由stackoverflow.com/suggested-edits/237242没有通过?它显示了如何按照最初提出的问题使用2个类来执行此操作。
GlassGhost 2012年

2
如果多个线程正在生成源事件,该事件将被正确同步怎么办?
Mike G

取决于刺激。每个听众将根据他们注册的顺序得到通知。(顺便说一句,我不明白您在这里使用多个线程的意思。监听器代码将在导致事件发生的同一线程上执行。)
aioobe 2012年

8
@GlassGhost:被拒绝,因为它基本上是完全重写。如果编辑可以修正拼写错误,格式设置和链接断开等问题,那么对其他人的答案进行编辑是不错的选择,但他们不应该从根本上改变内容。(某些例外情况适用于标有“社区Wiki”的帖子。)
cHao 2014年

1
Java没有内置的东西吗?我真的更喜欢以抽象模式执行此操作,而不是为每个事件实现for循环。
托马什Zato -恢复莫妮卡


21

您可能希望通过3种不同的方式进行设置:

  1. Thrower 代替 Catcher
  2. Catcher 代替 Thrower
  3. ThrowerCatcher内部在这个例子中另一个类的Test

我正在使用的GITHUB示例示例默认值为选项3,要尝试其他选项,只需取消注释Optional要成为主类的“”代码块的注释,然后将该类设置为文件中的${Main-Class}变量build.xml

抛出边码所需的4件事:

import java.util.*;//import of java.util.event

//Declaration of the event's interface type, OR import of the interface,
//OR declared somewhere else in the package
interface ThrowListener {
    public void Catch();
}
/*_____________________________________________________________*/class Thrower {
//list of catchers & corresponding function to add/remove them in the list
    List<ThrowListener> listeners = new ArrayList<ThrowListener>();
    public void addThrowListener(ThrowListener toAdd){ listeners.add(toAdd); }
    //Set of functions that Throw Events.
        public void Throw(){ for (ThrowListener hl : listeners) hl.Catch();
            System.out.println("Something thrown");
        }
////Optional: 2 things to send events to a class that is a member of the current class
. . . go to github link to see this code . . .
}

类文件中需要2件事来接收来自类的事件

/*_______________________________________________________________*/class Catcher
implements ThrowListener {//implement added to class
//Set of @Override functions that Catch Events
    @Override public void Catch() {
        System.out.println("I caught something!!");
    }
////Optional: 2 things to receive events from a class that is a member of the current class
. . . go to github link to see this code . . .
}

6
@GlassGhost:问题是main静态的,没有this静态函数中的东西。您需要创建一个new Catcher1()地方,然后传递该实例。1.5也不允许this在静态上下文中使用;我很确定它从未被允许。
cHao 2014年

6
@GlassGhost:使用的代码this在构造函数中,而不在中main。这就是为什么它起作用。将其移至main,我保证不会。这就是人们一直在试图告诉您的,您的答案正在试图做的。我不该死在github上的东西-我不在乎SO上的东西。而且您在SO上拥有的东西已损坏。
cHao 2014年

7
@GlassGhost:我不认为您的回答总体上是不够的。我看到的问题是该代码无法按原样工作-您正在尝试使用thisfrom main,它将无法在任何Java发行版中进行编译。如果该部分位于构造函数中,或者main创建new Catcher1()并使用而不是this,则即使在1.6+ 中,它也可以正常工作。
cHao 2014年

6
@GlassGhost:“已声明的static方法称为类方法。在未引用特定对象的情况下始终调用类方法。尝试使用关键字this或关键字引用当前对象super或引用任何周围环境的类型参数类方法主体中的声明会导致编译时错误。” - JLS对Java 5,§8.4.3.2

31
这是我见过的最奇怪的代码样式之一
Eric

4

以下内容并不完全相同,但很相似,我正在寻找一个片段来添加对接口方法的调用,但是发现了这个问题,所以我决定为那些像我这样搜索它的人添加这个片段。 :

 public class MyClass
 {
        //... class code goes here

        public interface DataLoadFinishedListener {
            public void onDataLoadFinishedListener(int data_type);
        }

        private DataLoadFinishedListener m_lDataLoadFinished;

        public void setDataLoadFinishedListener(DataLoadFinishedListener dlf){
            this.m_lDataLoadFinished = dlf;
        }



        private void someOtherMethodOfMyClass()
        {
            m_lDataLoadFinished.onDataLoadFinishedListener(1);
        }    
    }

用法如下:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
            @Override
            public void onDataLoadFinishedListener(int data_type) {
                }
            });
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.