10

おそらく、説明するのは少し難しいです。しかし、私はそれを試してみます;)

流暢なスタイルに従って、クラスのメソッドがクラス インスタンス自体 (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

}

しかし、この拡張クラスで別の継承ステップを実行するとき、(上位クラスの) メソッドの一般的な戻り値の型とクラスの説明自体 (スーパースーパークラスのメソッドなど) を定義しようとすると、問題が発生します。 class は拡張クラスの型ではなく、スーパークラスの型を返します。ただし、私の意図は、これらの流暢なスタイル メソッドが常に現在のクラスの型を返す必要があることです (上位クラスではありません)。

では、ジェネリックを利用してソリューションを定義することは可能ですか?

PS:簡単な回避策は、拡張クラスでこれらすべてのメソッドをオーバーライドし、それらを現在の型にキャストすることです。ただし、よりエレガントなソリューションに興味があります;)

4

4 に答える 4

4

あなたが試すことができます:

class A<T> { }

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

class C extends B<C> { }
于 2012-07-20T15:40:58.140 に答える
1

一般に「現在のクラスの型を返す」ことはできません。

あなたが上に投稿したコードでさえ安全ではありません:public class C extends A<B>は合法ですが、それを呼び出すdoSomething()と、 が期待されてBクラッシュします。

于 2012-06-21T18:15:50.043 に答える
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
于 2012-06-21T17:46:21.967 に答える
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;
    }
}
于 2012-06-22T18:05:13.440 に答える