小编典典

如何用编译时泛型验证替换运行时instanceof check

java

真正的Java泛型专家有点困惑…;)

假设我有以下两个接口:

interface Processor {
    void process(Foo foo);
}

interface Foo {
    Processor getProcessor();
}

例如,以下两个实现类:

static class SomeProcessor implements Processor {
    static final SomeProcessor INSTANCE = new SomeProcessor();

    @Override
    public void process(Foo foo) {
        if (foo instanceof SomeFoo) { // <-- GET RID OF THIS ?
            // process ((SomeFoo) foo)
        }
    }
}

class SomeFoo implements Foo {
    @Override
    public Processor getProcessor() {
        return SomeProcessor.INSTANCE;
    }
}

有什么方法可以使这两个接口通用,以至于我不需要instanceofprocess()函数中进行标记检查,而在我的代码的其他地方仍可以进行以下构造工作?

foo.getProcessor().process(foo);

(当然,我不知道我在处理哪个Foo子类)

换句话说:我正在寻找一种在对象中定义函数的方法,使其只能返回另一个对象,该对象处理包含该函数的对象的类型。注意:我不仅在谈论处理包含该函数的对象的某些最小公分母超类(上方:Foo),而且还涉及该对象的实际类(上方:SomeFoo)。

(除非我现在真的很愚蠢,否则这听起来似乎微不足道)。


阅读 309

收藏
2020-11-26

共1个答案

小编典典

这比我想的还要丑。我的看法:

interface Processor<F extends Foo<F>> {
    void process(F foo);
}

interface Foo<F extends Foo<F>> {
    Processor<F> getProcessor();
}

interface SomeFoo extends Foo<SomeFoo> {
    @Override
    SomeProcessor getProcessor();
}

interface SomeProcessor extends Processor<SomeFoo> {
    @Override
    void process(SomeFoo foo);
}

现在,将编译以下内容:

<F extends Foo<F>> void process(F foo) {
    foo.getProcessor().process(foo);
}

void process(Foo<?> foo) {
    foo.getProcessor().process(foo);
}

不会,因为编译器无法知道所传递的foo的实际类型是其类型参数的子类型,就像有人可以这样写:

    class Bar implements Foo<SomeFoo> { ... }

我们可以通过要求foo的子类型实现对其类型参数的转换来解决此问题:

abstract class Foo<F extends Foo<F>> {
    abstract Processor<F> getProcessor();

    abstract F getThis();
}

class SomeFoo extends Foo<SomeFoo> {
    @Override
    SomeFoo getThis() {
        return this;
    }

    @Override
    Processor<SomeFoo> getProcessor() {
        return new SomeProcessor();
    }
}

现在,我们可以写:

<F extends Foo<F>> void process(Foo<F> foo) {
    foo.getProcessor().process(foo.getThis());
}

并用

Foo<?> foo = ...;
process(foo);

为了易于使用,我建议将helper方法移到Foo类中:

abstract class Foo<F extends Foo<F>> {
    abstract Processor<F> getProcessor();

    abstract F getThis();

    void processWith(Processor<F> p) {
        p.process(getThis());
    }
}

更新:我认为newaccts更新的答案显示了一个更优雅的解决方案,因为它不需要递归类型界限。

2020-11-26