4

次のように定義されたインターフェイスがあります。

public interface AdditionalProcessing<Pre, Post> {
    public void postProcess(Pre pre, Post post);
}

NoAdditionalProcessingそして、それを拡張するクラスを作りたいと決心しました。実装のために何もしないノーオペレーションです。コンパイルする私の実装は次のとおりです。

public class NoAdditionalProcessing implements AdditionalProcessing {

    @Override
    public void postProcess(Object o, Object o2) {

    }
}

問題は、これを次のようなメソッド シグネチャに渡すときです。

public <I, O> O map(I source, Class<O> destinationClass, AdditionalProcessing<I, O> additionalProcessing) throws MappingException 

メソッド呼び出しで次のような警告が表示されます。

未チェックの割り当て: ...NoAdditionalProcessing から ...AdditionalProcessing

それら...は、私が除外したパッケージ名です。この警告を取り除く方法はありますか? NoAdditionalProcessing基本的には「なんでも受け付けます、関係ないから大丈夫」と定義したいんです。


私はこれを試しました:

public class NoAdditionalProcessing implements AdditionalProcessing<Object, Object>

しかし、渡す必要があるため、エラーが発生しますObject。私はもう試した

public class NoAdditionalProcessing implements AdditionalProcessing<? extends Object, ? extends Object>

しかし、それはコンパイルされません。

4

5 に答える 5

3

これは、@RussellZahniser ソリューションが @assylias ソリューションよりも優れていると考える理由の長いバージョンです (ただし、別のひねりも追加します)。

ジェネリックを使用するときはいつでも、サブタイプまたはスーパータイプを許可するかどうかを検討してください

最初はコンパイラが過度にペダンティックに見えるかもしれませんが、ジェネリクスには奇妙な逆の互換性があります。大まかに言うと、リンゴの袋は果物の袋ではありません. 果物の袋にはバナナを入れることができますが、りんごの袋には入れることができません。

したがって、ジェネリックを使用するときは常に、サブタイプ (消費用) またはスーパータイプ (生産用) を許可するかどうかを検討してください。

AdditionalProcessingあなたがコンバーターであると仮定すると、実際にはAdditionalProcessing<IN, OUT>.

では、AdditionalProcessing互換性があるのはいつですか?

タイプのコンバーターが必要であると仮定しますAdditionalProcessing<Fruit, Fruit>あらゆる種類の果物を受け入れる必要がありますが、どの種類の果物を返すかは問題ではありません。つまり、リンゴをオレンジに変える可能性があります。ただし、リンゴを石に変換するものであってはなりません。そうすると、オレンジに餌を与えることができず、果物が得られないからです。

したがって、コンバーターの場合、map関数は実際には次のようになります。

public <I, O> O map(I source, Class<O> destinationClass, 
    AdditionalProcessing<? super I, ? extends O> additionalProcessing)

以来:

? super I: 「少なくとも果物を受け入れます (しかし、何か他のものも受け入れます!)」.

? extends O: "ある種の果物を返します (ただし、リンゴだけかもしれません)".

果物の例は本当に価値があることがわかりました。

次にNoAdditionalProcessing、次のようになります。

public class NoAdditionalProcessing<TYPE>
  implements AdditionalProcessing<TYPE, TYPE> {
    @Override
    public void postProcess(Object o, Object o2) {
         // Actually I would have expected something like "return o1;"
    }
}

これは本質的に、最初の行でクレジットした 2 つの回答を融合したものです。ただし、あなたの質問から、あなたが望むかどうかを判断するのは困難superですextends。そのため、両方が合理的であり、両方が必要な場合があることを強調したいと思います.

通常、これはsuper入力タイプ(つまり、消費されたデータ) と出力タイプ (つまり、生成されたextendsタイプ)用になります。(ネストされたジェネリックではさらに厄介になります。)つまり、 a の場合、両方のスーパー タイプを受け入れるコンパレーターを許可する必要があります。ComapareTwoTypes<FIRST, SECOND>

パターンとしてのいくつかの例:

  • Validator<? super I, ? super O>

    スーパータイプのみで検証を実行している場合は許容されます。比較のために両方の型を消費し、何も生成しません

  • Converter<? super I, ? extends O>

    スーパータイプを受け入れることを選択する場合があり、戻り値を特定のスーパータイプに制限する場合があります。最初のタイプを消費し、2 番目のタイプを生成ます

両方が である例を思いつくのははるかに困難ですextends。Java コンパイラーは追加のヒントがないと確実に型を推測できないためです。これは、 コレクションの反変性のために、IおよびOそれ自体がジェネリック (別の型のコレクションなど) である場合に主に発生します。

ウィキペディアには、型の共分散と反分散に関する記事があり、ここで発生する状況に光を当てるのに役立つ可能性があります (残念ながら、この記事は少し理論的なものです)。しかし、コレクションは最も明白なケースです。この「リンゴの袋は果物の袋ではありません。バナナを入れることはできません」という例があったのはC++だったと思いますが、主なものは潜水艦を駐車場に置くことです(駐車場がある場合) -たくさんの車は一種の車の駐車場でしたが、そうではありません)。

于 2013-06-17T18:15:34.737 に答える
2

次のようにクラスを宣言できます。

public class NoAdditionalProcessing<Pre, Post> 
                       implements AdditionalProcessing<Pre, Post> {
     @Override public void postProcess(Pre pre, Post post) { /*no-op*/ }
}

その後、必要に応じて を作成できnew NoAdditionalProcessing<Object, Object>ます。

于 2013-06-17T17:46:13.840 に答える
1

警告を抑制する注釈を追加することで、警告をなくすことができます。

警告を取り除くには

@SuppressWarnings("unchecked")
public <I, O> O map(I source, Class<O> destinationClass, AdditionalProcessing<I, O> additionalProcessing) throws MappingException 
于 2013-06-17T17:39:36.243 に答える