12

できるだけユーザーフレンドリーな API を作ろうとしています。

持ってみましょう:

class B extends A {}

class A {
    A setX(){ ...; return this; }
}

今これ

B b = new B().setX();

は無効です。キャストする必要があります:

B b = (B) new B().setX();

ジェネリックを使用Aしてコンパイラに「この」型を認識させ、最初の方法を受け入れる方法はありますか? (new B<B>().setX()つまり、それは醜いです。)

この場合、Java で再入力が必要な理由はわかっています。setX()A を返す理由を説明しないでください ジェネリックがこれを解決できるかどうか尋ねています。

そして、「これが静的型付けの仕組みです」「ジェネリックでさえそれを助けることはできない」とまだ言いたい人は、次の有効な Java コードを検討してください。

Map<String, String> map = new HashMap(){{ put( "foo", new RuntimeException() );
String foo = map.get("foo");  // ClassCastException!!

したがって、ジェネリックスを使用すると、実際の型キャストがコードに表示されなくても CCE を取得できることがわかります。
これが、ジェネリックが明示的な型キャストを取り除くことを許可することを期待する理由です。

また、IIRC C++ ではそれが可能です

4

4 に答える 4

14

別の質問への回答の一部をここにコピーし、いわゆる「自己型」の必要性と Java での回避策を説明します。

メソッドチェーン

書く代わりに

foo.doA();
foo.doB();

多くの人はむしろ書きたいと思っています

foo.doA().doB();

残念ながら、この言語は、ますます望まれる機能になりつつあるにもかかわらず、メソッド チェーンを直接サポートしていません。回避策は、doA()を返すことfooです。少し汚れていますが許容範囲です。

ただしfoo、タイプ階層にある場合、回避策は壊れています

class Bar
    Bar doA()

class Foo extends Bar
    Foo doB();

foo.doA().doB(); // doesn't compile, since doA() returns Bar

そのため、この問題を解決するために特別な「自己型」を求める人もいます。This「自分型」を表すキーワードがあるとしましょう

class Bar
    This doA()

foo.doA().doB(); // works, doA() returns the type of foo, which is Foo

メソッド連鎖が「自己型」の唯一のユースケースであるように思われるため、言語はおそらくそれを導入することはありません (メソッド連鎖を直接サポートすることをお勧めします)。

人々は、ジェネリックがこの問題の回避策を提供することを発見しました

class Bar<This>
    This doA()

class Foo extends Bar<Foo>

Foo has a method "Foo doA()", inherited from Bar<Foo>

A extends B<A>これは、パターンの最も一般的な使用例です。これは、孤立した回避策/トリックです。A と B の間の関係にセマンティクスを追加しません。

Thisのように制約することも一般的な方法です。

class Bar<This extends Bar<This>>

それは醜くて役に立たないので、強くお勧めしません。それが何のためにあるのかを示すための規則として単に「これ」を使用してください。

于 2013-06-16T23:25:11.687 に答える
6

クラスAでこれを試してください:

public <T extends A> T setX() {
    return (T) this;
}

そして、あなたはそれをこのように使うことができます

B b = new B().setX();
于 2014-06-18T14:19:11.247 に答える
4

キャストが本当に気に入らない場合はB、メソッドをオーバーライドできます

@Override
public B setX() {
    super.setX();
    return this;
}
于 2013-06-16T23:20:54.357 に答える