Java中类型泛型的复杂情况

时间:2014-10-13 15:22:41

标签: java generics

我想在Java中有一个以某种方式引用自身的类型。

确切地说,我想要一个可以拥有监听器的命令类:

public abstract class GenericCommand<T> implements Future<T> {
    // ...
    private final List<GenericCommandListener<GenericCommand<T>>> listeners = new ArrayList<>();

    @SuppressWarnings("unchecked")
    public void addListeners(
            GenericCommandListener<GenericCommand<T>>... listeners) {
        this.listeners.addAll(Arrays.asList(listeners));
    }

    private void onValueAvailable() {
        for (GenericCommandListener<GenericCommand<T>> listener : listeners) {
            listener.onValueAvailable(this);
        }
    }
}

GenericCommandListener看起来像

public interface GenericCommandListener<T extends GenericCommand<?>> {
    public void onValueAvailable(T theCmd);
}

此命令的目的是发送到设备并生成某种类型的结果。

现在,我希望能够覆盖我的GenericCommand<T>,以便它实现一种特殊的命令,可能是FooCommand,它会产生Double

public class QueryValueCommand extends GenericCommand<Double> {
}

现在,我创建了这个类的实例,并希望它接受GenericCommandListener<QueryValueCommand>。但我不能这样做;我所能做的就是让它接受GenericCommandListener<GenericCommand<Double>>

我看到以下几种方式:

  1. ? super类的侦听器定义中执行? extendsGenericCommand的操作。我尝试了几种组合,但都没有工作,因为对象无法放入列表,或者调用不起作用。

  2. 更改Listener类的定义 - 但是如何?

  3. 以不同的方式定义GenericCommand类,以便它始终使用对完全正确类型的侦听器的引用:

    public abstract class GenericCommand<T> implements Future<T> {
        private final List<GenericCommandListener<MyExactTypeEvenIfSubclassing>> listeners = ...;
    }
    

    以便从中派生的QueryValueCommand接受GenericCommandListener<QueryValueCommand>

2 个答案:

答案 0 :(得分:2)

正如aruisdante所提议的,班级GenericCommand必须依靠自己:

public abstract class GenericCommand<C extends GenericCommand<C, T>, T> implements Future<T> {
    // ...
    private final List<GenericCommandListener<C, T>> listeners = new ArrayList<>();

    @SuppressWarnings("unchecked")
    public void addListeners(
            GenericCommandListener<C, T>... listeners) {
        this.listeners.addAll(Arrays.asList(listeners));
    }

    private void onValueAvailable() {
        for (GenericCommandListener<C, T> listener : listeners) {
            listener.onValueAvailable((C) this);
        }
    }
}

侦听器类也必须通过这种方式进行修改:

interface GenericCommandListener<C extends GenericCommand<C,T>, T>  {
    public void onValueAvailable(C theCmd);
}

现在,您可以声明:

public class QueryValueCommand extends GenericCommand<QueryValueCommand, Double>

你可以写:

QueryValueCommand command = new QueryValueCommand();
GenericCommandListener<QueryValueCommand, Double> listener = ...;

command.addListeners(listener);

答案 1 :(得分:0)

如果你这样实施GenericCommandListener

  public interface GenericCommandListener<T> {
    public <U extends GenericCommand<T>> void onValueAvailable(U theCmd);
  }

然后你应该能够像这样添加你的GenericCommand类的听众:

  public abstract class GenericCommand<T> implements Future<T> {
    private final List<GenericCommandListener<T>> list = new ArrayList<>();

    public <U extends GenericCommandListener<T>> void addListener(U listener) {
      list.add(listener);
    }

这有帮助吗?