Source<T>オブジェクトの純粋なプロデューサーである汎用インターフェースがあるとしTます。純粋なプロデューサーであることは、インターフェイスの契約の一部です。したがって、 を使用してできることは、 を持っている場合にも実行できるはずであるというのは妥当な期待です。Source<Foo>Source<? extends Foo>
ここで、この制限を の本体に適用する必要があります。これにより、誰かがその契約に反する方法でSource誤って使用しないようにすることができます。T
JDK の例
@Miserable.Variable が指摘するように、同等ではArrayList<Integer>ありません。これは、ジェネリック型として共変ではないためです。言い換えれば、は;の純粋なプロデューサーではありません。具体的には、このメソッドは を消費します。ArrayList<? extends Integer>ArrayListArrayList<T>TArrayListadd(T) T
Iteratorただし、またはのような純粋なプロデューサーであるジェネリック型がありますIterable。でできることは何でも、 で行うIterator<Integer>こともできますIterator<? extends Integer>。のような方法はありませArrayList.add(T)んIterator<T>。
Source<T>私のインターフェースが好きIterator<T>ではなく似ていることを確認したいだけですArrayList<T>。将来、誰かが をT消費するメソッド ( などadd(T)) を私のインターフェースに追加した場合、明示的なエラーが発生するようにしたいと考えています。
より複雑な例
タイプのパラメーターがTインターフェイスに表示されないようにするだけでは、完全な解決策にはなりません。Tまた、他のジェネリック型への引数として使用される可能性があることに注意する必要があります。たとえば、次のメソッドは では許可されませんSource<T>。
public void copyTo(List<T> destination);
卑劣なサブクラスがリストから読み取ろうとする可能性があるため、それはT-consumer と見なされます。でこのメソッドを呼び出すことはできませんSource<? extends Foo>。一方、これは許可されるべきです:
public void copyTo(List<? super T> destination);
Source<T>( のメソッドはを返すことはできませんがList<T>、 を返すことはできるという別の規則もありList<? extends T>ます。)
現在、実際のインターフェースは、多くのメソッドを使用して任意に複雑にすることができ、ルール自体もかなり複雑です。間違いを犯すのは非常に簡単です。だから私はこのチェックを自動化したい。
単体テストのトリック、静的アナライザー、コンパイラ/IDE プラグイン、注釈プロセッサ (たとえば、@Covariant注釈付きT)、またはこれを保証できるその他の手法やツールはありますか?