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

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

本文介绍了如何用编译时泛型验证替换运行时instanceof检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



假设我有以下两个接口:

 接口Processor {
void process(Foo foo);
}

interface Foo {
处理器getProcessor();
}

以及以下两个实现类:

 静态类SomeProcessor实现处理器{
static final SomeProcessor INSTANCE = new SomeProcessor();

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

类SomeFoo实现Foo {
@Override
公共处理器getProcessor(){
返回SomeProcessor.INSTANCE;






$ b

有没有办法使这两个接口通用这样我不需要在 process()函数中标记 instanceof 检查并仍然具有以下在我的代码的其他地方构建工作?

  foo.getProcessor()。process(foo); 

(当然,我不知道我正在处理的Foo的子类)换句话说:我正在寻找一种方法来定义一个对象中的函数,以便它只能返回另一个对象,该对象处理包含该对象的类型功能。注意:我不只是在谈论如何处理包含该函数的对象的最小公分母超类(上图:Foo),而是该对象的实际类(上面的:SomeFoo)。



(这可能听起来毫无意义,除非我现在真的很愚蠢......)

解决方案

这比我想象的更丑陋。我的看法:

 接口处理器< F extends Foo< F>> {
void process(F foo);
}

interface Foo< F extends Foo< F>> {
处理器< F> getProcessor();
}

接口SomeFoo扩展Foo< SomeFoo> {
@Override
SomeProcessor getProcessor();
}

接口SomeProcessor扩展Processor< SomeFoo> {
@Override
void process(SomeFoo foo);
}

现在,以下代码将被编译:

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

但是

<$ p ($ f $ f $ f $ f $)$ f $。
}

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

  class Bar实现Foo< SomeFoo> {...} 

我们可以通过要求foo的子类实现转换它们的类型参数:

pre $ abstract class Foo< F extends Foo< F>> {
抽象处理器< F> getProcessor();

abstract F getThis();
}

类SomeFoo扩展Foo< SomeFoo> {
@Override
SomeFoo getThis(){
return this;
}

@覆盖
处理器< SomeFoo> getProcessor(){
return new SomeProcessor();


$ / code $ / pre

现在,我们可以这样写:

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

并用

调用

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

为了便于使用,我建议将辅助方法移入Foo类中:

 抽象类Foo< F extends Foo< F>> {
抽象处理器< F> getProcessor();

abstract F getThis();

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


$ / code>

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


Got a little puzzle for a true Java Generics specialist... ;)

Let's say I have the following two interfaces:

interface Processor {
    void process(Foo foo);
}

interface Foo {
    Processor getProcessor();
}

and, for example, the following two implementing classes:

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;
    }
}

Is there some way to make the two interfaces generic in such a way that I don't need the marked instanceof check in the process() function and still have the following construct work elsewhere in my code?

foo.getProcessor().process(foo);

(where, of course, I don't know what subclass of Foo I'm dealing with)

In other words: I'm looking for a way to define a function in an object such that it can only return another object that processes the type of object that contained the function. Note: I'm not just talking about processing some least common denominator super-class of the object containing the function (above: Foo), but that object's actual class (above: SomeFoo).

(This is nowhere near as trivial as it may sound unless I'm really being stupid right now...)

解决方案

This is uglier than I thought. My take:

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);
}

Now, the following will compile:

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

but

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

doesn't, because the compiler can not know that actual type of the passed foo is a subtype of its type parameter, as somebody could write:

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

We can work around this by requiring the subtypes of foo to implement a conversion to their type parameter:

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();
    }
}

Now, we can write:

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

and invoke this with

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

To make it easy to use, I recommend moving the helper method into class Foo:

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

    abstract F getThis();

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

Update: I think newaccts updated answer shows a more elegant solution, as it does not need the recursive type bounds.

这篇关于如何用编译时泛型验证替换运行时instanceof检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 15:55