Java 具有多个继承类的泛型返回类型的自引用方法

Java 具有多个继承类的泛型返回类型的自引用方法,java,generics,inheritance,self-reference,Java,Generics,Inheritance,Self Reference,这可能有点难以描述。不过,我会试试;) 遵循fluent样式,类的方法通常返回类实例本身(如下所示) 当扩展这样一个fluent样式的类时,在第一个继承步骤中,通过泛型类型并在超类中将返回类型转换为这个泛型类型,可以相当容易地做到这一点 public class A<T extends A<T>> { public T doSomething() { // do something here return (T) this;

这可能有点难以描述。不过,我会试试;)

遵循fluent样式,类的方法通常返回类实例本身(如下所示)

当扩展这样一个fluent样式的类时,在第一个继承步骤中,通过泛型类型并在超类中将返回类型转换为这个泛型类型,可以相当容易地做到这一点

public class A<T extends A<T>> {

    public T doSomething() {

        // do something here

        return (T) this;
    }

}

public class B extends A<B> {

    // an extended class of class A

}
公共A类{
公共卫生服务{
//在这里做点什么
返回(T)这个;
}
}
公共类B扩展了A{
//A类的扩展类
}
但是,在这个扩展类上执行另一个继承步骤时,我在尝试定义方法的泛型返回类型(在上层类中)和类描述本身时遇到了麻烦,例如,超级类中的方法不会返回扩展类的类型,而是返回超类的类型。然而,我的意图是这些fluent风格的方法应该总是返回当前类的类型(而不是上层类)

那么,是否有可能通过使用泛型来定义解决方案


PS:我知道,一个简单的解决方法可能是重写扩展类中的所有这些方法,并将它们强制转换为当前类型。但是,我对更优雅的解决方案感兴趣;)

您可以这样做:

public class TestFluent<T extends TestFluent<?>> {

    public T get() {
        return (T) this;
    }

    public static void main(final String[] args) {
        TestFluent2<TestFluent2<?>> f2 = new TestFluent2<TestFluent2<?>>();
        TestFluent2<?> result2 = f2.get();

        TestFluent3<TestFluent3<?>> t3 = new TestFluent3<TestFluent3<?>>();
        TestFluent3<?> result3 = t3.get();

        System.out.println(result2);
        System.out.println(result3);
    }
}

class TestFluent2<T extends TestFluent2<?>> extends TestFluent<T> {
}

class TestFluent3<T extends TestFluent3<?>> extends TestFluent2<T> {
}
通常不可能“返回当前类的类型”


即使您在上面发布的代码也是不安全的:
public class C扩展了A
是合法的,但是在其上调用
doSomething()
,期望A
B
,将会崩溃。

使用委派来实现可扩展的fluent接口。优点:没有演员。缺点:冗长

public interface FluentGranddad< C extends FluentGranddad< C > > {
    C appendFoo( Foo foo );
}
public interface FluentDad< C extends FluentDad< C > > extends FluentGranddad< C > {
    C appendBar( Bar b );
}
public interface FluentKid< C extends FluentKid< C > > extends FluentDad< C > {
    C appendSplat( Splat s );
}

public class Babbler implements FluentKid< Babbler > {
    FluentDad< ? > dad;
    public Babbler( FluentDad< ? > dad ) {
        this.dad = dad;
    }

    // delegation methods
    @Override public Babbler appendFoo( Foo foo ) {
        dad.appendFoo( foo );
        return this;
    }
    @Override public Babbler appendBar( Bar bar ) {
        dad.appendBar( bar );
        return this;
    }

    // example instance method
    @Override public Babbler appendSplat( Splat s ) {
        dad.getState().append( s.toString() );
        return this;
    }
}
公共接口FluentGrandad>{
C附录Foo(Foo-Foo);
}
公共接口FluentDad>扩展FluentGrandad{
C.钢筋(钢筋b);
}
公共接口FluentKid>扩展FluentDad{
C附属物(附属物s);
}
公共类Babbler实现FluentKid{
FluentDad<?>dad;
公共唠叨者(FluentDad<?>dad){
这个。爸爸=爸爸;
}
//委托方式
@覆盖公共语言程序appendFoo(Foo-Foo){
爸爸,阿潘福(福);
归还这个;
}
@覆盖公共语言附加条(Bar){
爸爸,我是巴(巴);
归还这个;
}
//实例法
@覆盖公共语言附加程序(Splat s){
dad.getState().append(s.toString());
归还这个;
}
}
您可以尝试:

class A<T> { }

class B<T extends A<? super T>> extends A<T> { }

class C extends B<C> { }
class A{}

B类可能相关的问题:是的,我知道这是我目前应用的简单解决方法。然而,在引入新的扩展层时,总是重复这一点有点麻烦(从我的观点来看)。是的,这看起来有点前途。我以前也尝试过使用通配符,但还没有找到合适的解决方案。。。。因为它是公共类B扩展A,而不是公共类C扩展A;)我的意思是,定义
公共类C扩展A
之后,定义
公共类B扩展A
是合法的,不是吗?。。。当然,这是合法的。但是,它没有导致预期的行为,或者?(…无论如何…)然后当你做
cfoo=。。。;B bar=食物剂量()它将崩溃。所以这是不安全的,这不是我想做的:我想做:B foo=。。。;foo.doSomething().doSomethingElse().doSomethingDifferent()。。。所以它总是返回B(自引用)。因此,请不要将所描述的用例与其他东西混淆。
public interface FluentGranddad< C extends FluentGranddad< C > > {
    C appendFoo( Foo foo );
}
public interface FluentDad< C extends FluentDad< C > > extends FluentGranddad< C > {
    C appendBar( Bar b );
}
public interface FluentKid< C extends FluentKid< C > > extends FluentDad< C > {
    C appendSplat( Splat s );
}

public class Babbler implements FluentKid< Babbler > {
    FluentDad< ? > dad;
    public Babbler( FluentDad< ? > dad ) {
        this.dad = dad;
    }

    // delegation methods
    @Override public Babbler appendFoo( Foo foo ) {
        dad.appendFoo( foo );
        return this;
    }
    @Override public Babbler appendBar( Bar bar ) {
        dad.appendBar( bar );
        return this;
    }

    // example instance method
    @Override public Babbler appendSplat( Splat s ) {
        dad.getState().append( s.toString() );
        return this;
    }
}
class A<T> { }

class B<T extends A<? super T>> extends A<T> { }

class C extends B<C> { }