具有侦听器的抽象Java类,该类在其回调中使用具体类

时间:2019-05-13 03:47:14

标签: java generics

我想要一个像这样的抽象Java类:

abstract class AbstractFoo<F extends AbstractFoo<F, L>, L extends FooListener<F, L>> {
  private final Class<L> listenerClass;
  protected AbstractFoo(Class<L> listenerClass) {
    this.listenerClass = listenerClass;
  }

  interface FooListener<F extends AbstractFoo<F, L>, L extends FooListener<F, L>> {
    void callback(F foo);
  }

  // Bar might implement FooListener, but I don't control it,
  // so I have no guarantee
  public void externalMethod(Bar bar) {
    if (listenerClass.isInstance(bar)) {
      L listener = listenerClass.cast(bar);

      listener.callback(this); // does not compile
    }
  }
}

listener.callback(this);无法编译,因为不能保证thisF的类型相同。能否以某种方式保证Fthis的超类型?

1 个答案:

答案 0 :(得分:1)

您想要做的是使用泛型在Java中模拟SELF类型。有关某些方法,请参见this linka different site。但是,例如,无法强制F(或SELF类型)实际上是同一类型(请参见ConcreteFoo2的类型参数):

static class Bar implements FooListener<ConcreteFoo, Bar> {

    @Override
    public void callback(final ConcreteFoo foo) {
        // TODO Auto-generated method stub

    }

}

static class ConcreteFoo2 extends AbstractFoo<ConcreteFoo, Bar> {

    protected ConcreteFoo2(final Class<Bar> listenerClass) {
        super(listenerClass);
    }

}

static class ConcreteFoo extends AbstractFoo<ConcreteFoo, Bar> {

    protected ConcreteFoo(final Class<Bar> listenerClass) {
        super(listenerClass);
    }

}

除了继续采取这种方式,我首先考虑一下导致您来到这里的设计选择:

  • 听众真的需要了解具体的课程吗?

  • AbstractFoo是否真的需要知道侦听器类的具体实现?

也许解决方案实际上是更少的类型参数,仅依赖于接口。


编辑:如果不想强制转换(F) this,一个可能的解决方案是提供一种抽象方法protected abstract F getSelf();,具体实现可通过返回this来实现。

例如,请参见以下简化代码:

static final class Bar implements FooListener<ConcreteFoo> {

    @Override
    public void callback(final ConcreteFoo foo) {
        // TODO Auto-generated method stub

    }

}

static final class ConcreteFoo extends AbstractFoo<ConcreteFoo> {

    protected ConcreteFoo(final Class<? extends FooListener<ConcreteFoo>> listenerClass) {
        super(listenerClass);
    }

    @Override
    protected ConcreteFoo getSelf() {
        return this;
    }

}

static abstract interface FooListener<FOO extends AbstractFoo<FOO>> {

    void callback(FOO abstractFoo);
}

static abstract class AbstractFoo<SELF extends AbstractFoo<SELF>> {

    private final Class<? extends FooListener<SELF>> listenerClass;

    protected AbstractFoo(final Class<? extends FooListener<SELF>> listenerClass) {
        this.listenerClass = listenerClass;
    }

    protected abstract SELF getSelf();

    // Bar might implement FooListener, but I don't control it,
    // so I have no guarantee
    public void externalMethod(final Bar bar) {
        if (listenerClass.isInstance(bar)) {
            final FooListener<SELF> listener = listenerClass.cast(bar);

            listener.callback(getSelf()); // compiles
        }
    }
}