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

时间:2012-06-21 17:20:41

标签: java generics inheritance self-reference

描述起来可能有点困难。但是,我会试试;)

遵循流畅的风格,类的方法通常会返回类实例(this)。

public class A {

    public A doSomething() {

        // do something here

        return this;
    }

}

当扩展这样一个流畅的样式类时,可以通过泛型类型在第一个继承步骤中相当容易地执行此操作,并将返回类型转换为超类中的此泛型类型。

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

}

但是,当在这个扩展类上做另一个继承步骤时,我在尝试定义方法的泛型返回类型(在上层类中)和类描述本身时遇到了麻烦,例如,在超级超类不会返回扩展类的类型,而是返回超类的类型。但是,我的意图是这些流畅的样式方法应该总是返回当前类的类型(而不是上层类)。

那么可以通过利用泛型来定义解决方案吗?

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

4 个答案:

答案 0 :(得分:4)

你可以尝试:

class A<T> { }

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

class C extends B<C> { }

答案 1 :(得分:1)

你可以这样做:

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

这将返回:

TestFluent2@7919298d
TestFluent3@62f72617

答案 2 :(得分:1)

通常无法“返回当前类的类型”。

即使您上面发布的代码不安全,public class C extends A<B>也是合法的,但是在doSomething()上调用B会导致{{1}}崩溃。

答案 3 :(得分:0)

使用委托实现可扩展的流畅接口。优点:没有演员。缺点:详细。

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