3

鉴于 JNotify 的以下示例,我在理解implements时遇到了一些麻烦。class Listner实现 JNotifyListener 的方法—— fileRenamed、、fileModified等等——但将返回类型从 void 修改为 Integer是否是有效的 Java 语法?

我想在 JNotify 之上编写一个 Clojure 库,并在未来拥有 Clojure 代码块,直到 Listener 的方法之一返回。

  class Listener implements JNotifyListener {
    public void fileRenamed(int wd, String rootPath, String oldName,
        String newName) {
      print("renamed " + rootPath + " : " + oldName + " -> " + newName);
    }
    public void fileModified(int wd, String rootPath, String name) {
      print("modified " + rootPath + " : " + name);
    }
    public void fileDeleted(int wd, String rootPath, String name) {
      print("deleted " + rootPath + " : " + name);
    }
    public void fileCreated(int wd, String rootPath, String name) {
      print("created " + rootPath + " : " + name);
    }
    void print(String msg) {
      System.err.println(msg);
    }
  }
4

3 回答 3

3

回应 OP 的澄清评论:

对,这是观察者模式的一个简单示例:

public interface JNotifyListener {

    void fileRenamed(int wd, String rootPath, String oldName, String newName);

    void fileModified(int wd, String rootPath, String name);

    void fileDeleted(int wd, String rootPath, String name);

    void fileCreated(int wd, String rootPath, String name);
}

public enum Type {

    RENAMED,
    MODIFIED,
    DELETED,
    CREATED;
}

public class FileChangeEvent {

    final Type type;
    final int wd;
    final String rootPath;
    final String name;
    final String newName;

    public FileChangeEvent(Type type, int wd, String rootPath, String name, String newName) {
        this.type = type;
        this.wd = wd;
        this.rootPath = rootPath;
        this.name = name;
        this.newName = newName;
    }

    public FileChangeEvent(Type type, int wd, String rootPath, String name) {
        this(type, wd, rootPath, name, null);
    }

    public int getWd() {
        return wd;
    }

    public String getRootPath() {
        return rootPath;
    }

    public String getName() {
        return name;
    }

    public String getNewName() {
        return newName;
    }
}

public interface FileChangeEventListener {

    void notify(FileChangeEvent fileChangeEvent);
}

public class FileChangeEventNotifyer implements JNotifyListener {

    final Collection<FileChangeEventListener> listeners = new ConcurrentLinkedQueue<FileChangeEventListener>();

    @Override
    public void fileRenamed(int wd, String rootPath, String oldName, String newName) {
        notifyAll(new FileChangeEvent(Type.RENAMED, wd, rootPath, oldName, newName));
    }

    @Override
    public void fileModified(int wd, String rootPath, String name) {
        notifyAll(new FileChangeEvent(Type.MODIFIED, wd, rootPath, name));
    }

    @Override
    public void fileDeleted(int wd, String rootPath, String name) {
        notifyAll(new FileChangeEvent(Type.DELETED, wd, rootPath, name));
    }

    @Override
    public void fileCreated(int wd, String rootPath, String name) {
        notifyAll(new FileChangeEvent(Type.CREATED, wd, rootPath, name));
    }

    private void notifyAll(final FileChangeEvent changeEvent) {
        for (final FileChangeEventListener changeEventListener : listeners) {
            changeEventListener.notify(changeEvent);
        }
    }

    public void registerListener(final FileChangeEventListener eventListener) {
        listeners.add(eventListener);
    }

    public void unregisterListener(final FileChangeEventListener eventListener) {
        listeners.remove(eventListener);
    }
}

您可以看到 a classonly 需要实现FileChangeEventListener并将其兴趣注册到 main FileChangeEventNotifyer。然后它将notify使用事件调用其方法。

这里有几个常见的陷阱。一个是这个实现不使用synchronized,因此如果一个类在事件发生时被注册,它可能会错过一个通知。优点是这是非阻塞的。因此,由您决定是否最好使用非阻塞集合或阻塞集合。

此外,您要么需要确保所有已注册的侦听器事后都未注册,否则它们会堆积起来,最终可能导致内存泄漏。

我已经将它实现为一个单一FileChangeEventType- 显然你可以有一个父FileChangeEvent类,然后用类型的子类扩展它。同样,这取决于您的需求。

无论如何,这应该让你开始。

于 2013-04-22T19:20:24.437 回答
3

No. The return value type in the signature of an implementation must match the return value type of the interface it implements either with an exact match or with an implementing/extending type.


Response to comment (not to original question)

interface I {
  A foo();
}
class A {}
class B extends A {}
class C implements I {
  public B foo() { return null; }
}

The Java 6 Compiler accepts the code above, which implies the return value is covariant at override time, so the commenters are correct that the match need not be exact.

于 2013-04-22T18:30:28.213 回答
0

在 Clojure 方面,考虑使用 promise/deliver 而不是 future。然后 Listener 中的方法可以交付给 Promise。 http://clojuredocs.org/clojure_core/clojure.core/promise

如果这是针对库的,最好传递一个函数而不是使用future 或promise。这将允许库的用户传入他们自己的闭包,而不必引入另一个线程更改。

于 2013-04-22T20:08:23.473 回答