1

これはおそらく以前に何らかの形で尋ねられたことがありますが、まだ解決できないので、ここで集合的な知恵を求めようと思いました。私はそのようなインターフェースを持っています - 役に立つかもしれないので、いくつかのコメントを残しました。

/** Technical note: this generic binding is known as F-bound where class
 * T is 'the worked-on class' by Splittable i.e. the implementing class.
 */
interface Splittable <T extends Element & Splittable<T>> {


/** Returns an object of the same class which has been split off at
 * the point given.
 */ 
public T splitOff(double at);


/** Appends the object provided, which must be of the same class, to
 * this object.
 */
public void append(T el);
}

したがって、コンパイル時にわからない要素に取り組んでいます。

if (el instanceof Splittable) {
    if (nextEl.getClass == el.getClass) {
        // same class so join them
        ((Splittable)el).append(nextEl);
    }
}

そして、それがコンパイラの警告を受け取る場所です-生の型Splittableのメンバーとしてのappend(T)へのチェックされていない呼び出し。

Element サブクラスでは、両方を試しました

SubClassEl extends Element implements Splittable

SubClassEl extends Element implements Splittable<SubClassEl>

警告に違いはありません。

また、append() を呼び出す時点で、私は試しました

((Splittable)el).splitOff(x).append(nextElement)

ただし、コンパイラは、splitOff が Splittable を返す必要があることを認識せず、Element のみを返します。

何か案は?

4

1 に答える 1

4

ここで起こっているのは、ジェネリック型チェックを「オプトアウト」する生の型を使用していることです。その場合、Tは に消去されElementます。Javaチュートリアルから:

複数の境界が使用されている場合、境界で言及されている最初の型が型変数の消去として使用されます。

コードを警告なしでコンパイルする方法に関しては、現在の設計では不可能な場合があります。Elementおよび キャストを使用したプレーンなs での作業は、 oninstanceofで宣言された再帰的にバインドされた型パラメーターとうまく混ざりませんSplittable

生の型を避けて、私が得ることができる最も近いものはこれでした:

static <T extends Element & Splittable<T>> void maybeAppend(T el1, Element el2) {
    if (el1.getClass() == el2.getClass()) {
        @SuppressWarnings("unchecked") // arguments' runtime types are equal
        final T el2WithNarrowedType = (T)el2;
        el1.append(el2WithNarrowedType);
    }
}

...

if (el instanceof Splittable<?>) {
    maybeAppend(el, nextEl); //compiler error
}

これはまだコンパイルされません。型パラメーターがないと、それelが anであり、独自の型のElementaであると表現する方法がないからです。Splittable

私はここで同様の問題に答えました: Passing a runtime resolve parameter to a method that has multiple bound type, compilation error。生の型を使用しない最も近い解決策は、特定のコンパイラでしか機能しない主要なハックでした。OPは生のタイプを使用することになりました。

自己入力を避け、代わりに次のような実装を検討することをお勧めします。

interface ElementSplitter<T extends Element> {

    T splitOff(T element, double at);

    void append(T element, T appendedElement);
}

実装splitOffと機能が特定の派生appendのプライベート メンバーへのアクセスを必要とする場合、回避策はそれをネストされたクラスにすることです。次に例を示します。Element

class SubClassEl extends Element {

    ...

    static class Splitter implements ElementSplitter<SubClassEl> {
        ...
    }
}

Splittableあなたが書いたjavadocに気づきました:

技術的な注意: このジェネリック バインディングは F バウンドとして知られています。ここで、classは実装クラスTによって「処理されたクラス」です。Splittable

真の自己型付けはJavaではサポートされていないことに注意してください.あなたが持っているのは、再帰的にバインドされた型パラメーターであり、これはおそらく自己型ですが、必ずしもそうではありません. このパターンとその落とし穴の詳細については、こちらの回答を参照してください。

于 2013-05-30T14:45:50.857 に答える