避免泛型类型的表格Foo <actualtype extends =“”foo <actualtype =“”>&gt;

时间:2015-05-21 19:36:43

标签: java generics

我经常发现自己想要编写

形式的泛型类定义
public class Foo<ActualType extends Foo<ActualType>>

例如,在这样的设置中:

public interface ChangeHandler<SourceType> {
    public void onChange(SourceType source);
}


public class Foo<ActualType extends Foo<ActualType>> {

    private final List<ChangeHandler<ActualType>> handlers = new ArrayList<>();

    public void addChangeHandler(ChangeHandler<ActualType> handler) {
        handlers.add(handler);
    }

    @SuppressWarnings("unchecked")
    protected void reportChange() {
        for (ChangeHandler<ActualType> handler: handlers)
            handler.onChange((ActualType) this);
    }
}


public class Bar extends Foo<Bar> {
    // things happen in here that call super.reportChange();
}


public static void main(String[] args) throws IOException {

    Bar bar = new Bar();
    bar.addChangeHandler(new ChangeHandler<Bar>() {

        @Override
        public void onChange(Bar source) {
            // Do something with the changed object
        }
    });
}

这里的变化事件只是一个例子。这更像是一个普遍的问题,每当我想让超级班级提供个性化的功能时,我就会遇到这个问题。对于每个特定的子类(不确定如何更好地表达这一点......在上面的例子中&#34;个性化&#34;事实是ChangeHandler被实际的子对象调用type(Bar)不是调用处理程序的超类(Foo)的类型。

这种方法对我来说似乎有些混乱。它实际上允许潜在的问题,因为没有什么能阻止我定义:

public class Baz extends Foo<Bar> { /* ... */ }

有更清洁的选择吗?

圣杯将是一个总是被定义为包含当前类的类型参数,就像this.getClass()的静态版本一样,它允许我写这样的东西:

public class Foo {

    private final List<ChangeHandler<this.Class>> handlers = new ArrayList<>();

    public void addChangeHandler(ChangeHandler<this.Class> handler) {
        handlers.add(handler);
    }

    protected void reportChange() {
        for (ChangeHandler<this.Class> handler: handlers)
            handler.onChange(this);
    }
}

对于类型为this.Class的类,Bar等于Bar

2 个答案:

答案 0 :(得分:0)

这是一个非常抽象的问题。在我看来,简短的回答&#34;如何使这个更清洁&#34;是:只在需要的地方使用泛型。

public class List<T extends List<T>>

这是什么意思表达(替代)?一个只允许保持(T扩展)其他列表的列表,这些列表本身就是我们之前知道的Ts(List),它们只是允许持有的列表......等等。有点通告,我不知道你最终会怎么样?

public interface ChangeHandler<SourceType> {
    public void onChange(SourceType source);
}

为什么要在这里使用泛型?如果您想拥有一个可以处理多种资源类型的更改处理程序,那么您可以创建一个所有实际源继承的超类,或者创建一个由源实现的接口。像这样,您可以准确指定源所公开的内容。或者,源可以在通知时创建源对象而不是传递&#34;这个&#34; (然后它更像是一条消息)。例如:

public interface ChangeHandler {
    public void onChange(Source source);
}

public abstract class Source {
    private List<ChangeHandler> handlers;
    protected int nr;
    public Source(int nr) {
      this.nr = nr;
    }
    public abstract Something getSomething();
    public String toString() {
        return "SRC" + nr;
    }
    ...
    private notify(int index) {
        handlers.get(i).onChange(this);
    }
}

public class Foo extends Source {
    public Foo(int nr) {
        super(nr);
    }
    public String toString() {
        return super.toString() + "Foo";
    }
    public Something getSomething() {
        return new Something();
    }
}

你永远不需要演员......或者你呢?我不确定我是否理解这个问题。

答案 1 :(得分:0)

我建议我们只使用<This>来表示“自我类型”。不需要绑定,因为它看起来很复杂,没有表达意图,也无法强制执行约束。

public class Foo<This> {

    private final List<ChangeHandler<This>> handlers = new ArrayList<>();

    public void addChangeHandler(ChangeHandler<This> handler) {
        handlers.add(handler);
    }

    @SuppressWarnings("unchecked")
    protected void reportChange() {
        for (ChangeHandler<This> handler: handlers)
            handler.onChange( (This)this );
    }
}

注意投射(This)this

另见Java generics: Use this type as return type?