4

そのようなインターフェースがあるとします

public interface Foo<Ret, Arg> {
    public Ret doSomething(Arg arg);
}

そして、パッケージの可視性のみを持つ具体的な実装クラス。

class FooImpl<Ret, Arg1, Arg2> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Arg2> {
    // This class also implements something else making use of Arg2, so you cannot safely remove it
    // But nothing relating to Arg2 is needed to create a FooImpl
}

(これがどのように発生するかの例は、2 つのインターフェイスによって宣言されたFooand Barin FooImplforwards メソッドを 1 つの varargs メソッドに実装することです)

FooImplここで、 a を aとして返す静的メソッドが同じパッケージのどこかにあるとしますFoo。を使用できると考える人がいるかもしれreturn new FooImpl<Ret, Arg1, ?>(...)ませんが、実際には使用できません (たとえば、具体的なダミー型を として使用する必要がありますArg2) return new FooImpl<Ret, Arg1, Object>(...)

Foo特にインターフェイスとパッケージの可視性FooImplが静的メソッドを使用しているものから効果的に非表示になっているという事実として、これがなぜなのか考えはありますか? 具体的な型が必要なのBar部分に到達するために、まだある程度リフレクションを使用できるという事実のためですか?FooImpl

4

2 に答える 2

4

これはあなたの特定のデザインとは何の関係もないと思います。

ワイルドカードを使用して型をインスタンス化することはできません。

これも機能しません:

return new ArrayList<?>();

そして、もしそうなら、それは他に何かをするだろうか

return new ArrayList<Object>();

具体的なクラスが必要ですが、それはファクトリメソッドシグネチャでそれを表示する必要があるという意味ではありません。

static <A,B> Foo<A,B> makeFoo(){
    return new FooImpl<A,B, SomeTypeThatNoOneNeedsToSee>();
}
于 2012-09-10T07:22:32.893 に答える
1

Java コンパイラーは、スマートにならないように努めています。正しいコードを生成するためになんらかの情報を必要としないことが明らかであるにもかかわらず、それでも文句を言う状況はたくさんあります。Java が発明されたとき、世界は、どんなに危険で愚かでも、すべてをコンパイルしようとするずさんな態度で C を見ていました。の目標javacは、人々が自分の足を簡単に撃てないようにすることでした。

したがって、あなたが言及した理由があると想定していますArg2- 何かに必要でなければ、コードにそれを入れていないはずです。

ソリューション:

  1. 実装時に型を割り当てますBarclass FooImpl<Ret, Arg1> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Object>
  2. を作成しますBetterFooImpl<Ret, Arg1> extends FooImpl<Ret, Arg1, Object>。これにより、API のコンシューマーから 3 番目の型引数が隠されます。
  3. の 3 番目のパラメーターを削除してみてくださいBar
  4. ジェネリックは慎重に使用してください。驚くかもしれませんが、ジェネリックがうまく機能しない場合があります。これは通常、@SuppressWarningアノテーションの急増を引き起こす微妙な実装の詳細が原因です。これが発生した場合は、SO で質問し、理解できる解決策が見つからない場合は、ジェネリックを削除します。ジェネリックの迷路を抜け出す巧妙な方法を見つけるよりも、保守しやすいコードを書くことが重要です。
于 2012-09-10T07:32:52.380 に答える