Java:在超类方法签名中返回子类

Posted

技术标签:

【中文标题】Java:在超类方法签名中返回子类【英文标题】:Java: returning subclass in superclass method signature 【发布时间】:2012-06-13 16:14:09 【问题描述】:

我正在解决一个问题,其中有几个Foo 的实现,伴随着几个FooBuilder。虽然Foo 共享几个需要设置的公共变量,但它们也有不同的变量,需要它们各自的FooBuilder 来实现一些特定的功能。为简洁起见,我想让FooBuilder 的设置器使用方法链接,例如:

public abstract class FooBuilder 
  ...

  public FooBuilder setA(int A) 
    this.A = A;
    return this;
  

  ...

public class FooImplBuilder extends FooBuilder
  ...
  public FooImplBuilder setB(int B) 
    this.B = B;
    return this;
  
  public FooImplBuilder setC(int C) 
    this.C = C;
    return this;
  
  ...

等等,有几个不同的FooBuilder 实现。这在技术上可以满足我的所有需求,但是,这种方法在执行方法链接时对方法调用的顺序很敏感。以下有方法未定义的编译错误:

someFoo.setA(a).setB(b)...

要求开发人员考虑链中方法调用的顺序。为了避免这种情况,我想让FooBuilder 中的设置器以某种方式返回实际的实现子类。但是,我不确定如何执行此操作。最好的方法是什么?

【问题讨论】:

另外,它要么强制在任何地方强制转换,要么阻止您在需要时更改超类的属性。 【参考方案1】:

这是一个很好的问题,也是一个真正的问题。

如 Jochen 的回答中所述,在 Java 中处理它的最简单方法可能涉及使用泛型。

在Using Inheritance with Fluent Interfaces 的这篇博文中有很好的讨论和合理的解决方案,它将泛型与在构建器子类中覆盖的getThis() 方法的定义相结合,以解决总是返回构建器的问题正确的类。

【讨论】:

我喜欢这个解决方案。比我提出的要复杂得多,但也更灵活,最终更优雅。 只是总结链接的博客,并删除单独的构建器:public abstract class X<B extends X<?>>public int a;public B setA(int foo)this.a=foo;return getThis();public abstract B getThis();public class Y extends X<Y>public int b;public Y setB(int bar)this.b=bar;return getThis();public Y getThis()return this;【参考方案2】:

找到this excellent answer我现在分享它。

public class SuperClass<I extends SuperClass>

    @SuppressWarnings( "unchecked" ) // If you're annoyed by Lint.
    public I doStuff( Object withThings )
    
        // Do stuff with things.
        return (I)this ; // Will always cast to the subclass. Causes the Lint warning.
    


public class ImplementationOne
extends SuperClass<ImplementationOne>
 // doStuff() will return an instance of ImplementationOne

public class ImplementationTwo
extends SuperClass<ImplementationTwo>
 // doStuff() will return an instance of ImplementationTwo

【讨论】:

SuperClass&lt;I extends SuperClass&lt;I&gt;&gt; 摆脱“参数化类的原始使用...”【参考方案3】:

泛型可能是这里的方法。

如果你声明 setA() 这样的东西(伪代码)

<T> T setA(int a)

编译器应该能够找出真正的类型,如果不能,你可以在代码中给出提示

obj.<RealFoo>setA(42)

【讨论】:

+1:egalluzzo.blogspot.com/2010/06/… 对这种策略有很好的描述 编译器能够找出链式方法调用中的类型,并且为每个方法调用重复类型几乎不是一种选择。 @DonRoby:您为什么不将其发布为答案?它恰好是比 Jochen 更好的解决方案,当然值得一票;-)

以上是关于Java:在超类方法签名中返回子类的主要内容,如果未能解决你的问题,请参考以下文章

Java协变式覆盖(Override)和泛型重载(Overload)

是否可以在超类对象上调用子类的方法?

Java随笔一

Python 覆盖子类中方法返回的类型提示,无需重新定义方法签名

Java超类对象引用访问子类对象

马凯军201771010116《面向对象程序设计(java)》第七周学习总结