の有界パラメータ<T extends D<T>>
の代用として有効ではありません確かに - これらの「自己タイプ」はしばしば、サブタイプが自分のタイプを正確に返すように制約するために使用されます。次のようなものを考えてみましょう:
public interface Operation {
// This bit isn't very relevant
int operate(int a, int b);
}
public abstract class AbstractOperation<T extends AbstractOperation<T>> {
// Lets assume we might need to copy operations for some reason
public T copy() {
// Some clever logic that you don't want to copy and paste everywhere
}
}
クール - 私たちは、サブクラスに特異的であることができる便利な演算子を持つ親クラスを持っています。たとえば、AddOperation
を作成した場合、一般的なパラメータは何ですか?そのため、「再帰的」の一般的な定義で、これが唯一のAddOperationたちを与えることができます。
public class AddOperation extends AbstractOperation<AddOperation> {
// Methods etc.
}
ので、copy()
方法はAddOperation
を返すことが保証されます。
public class SubtractOperation extends AbstractOperation<AddOperation> {
// Methods etc.
// Because of the generic parameters, copy() will return an AddOperation
}
ジェネリック型は、その境界内にないので、これは、コンパイラによって拒否されます。今、私たちは愚かな、または悪意のある、または創造的、または何だと想像し、このクラスを定義するために試すことができます。これは非常に重要です。つまり、親クラスでは、具体的な型がわからなくても(コンパイル時に存在しないクラスであっても)、copy()
メソッドはインスタンスを返しますその同じサブクラスの
あなたは、単にC<T extends C>
と一緒に行った場合、SubtractOperation
のこの奇妙な定義は法的だろう、とあなたはT
が、その場合には何であるかについての保証を失う - それゆえ減算演算は、追加操作に自身をコピーすることができます。
これは悪意のあるサブクラスからクラス階層を保護することではなく、コンパイラが関連する型についてより強力な保証を提供するということです。 copy
を別のクラスのaltogtherから任意のOperation
にコールしている場合は、いずれかのフォーメーションで結果が同じクラスであることが保証され、もう一方はキャストが必要です(は正しくキャストできません上記のSubtractOperation)。例えば、このような
何か:
// This prelude is just to show that you don't even need to know the specific
// subclass for the type-safety argument to be relevant
Set<? extends AbstractOperation> operations = ...;
for (AbstractOperation<?> op : operations) {
duplicate(op);
}
private <T extends AbstractOperation<T>> Collection<T> duplicate(T operation) {
T opCopy = operation.copy();
Collection<T> coll = new HashSet<T>();
coll.add(operation);
coll.add(opCopy);
// Yeah OK, it's ignored after this, but the point was about type-safety! :)
return coll;
}
T
からduplicate
の最初の行に割り当てがタイプセーフあなたが提案した2つの境界の弱いとならないので、コードはないだろうコンパイル。 の場合でも、すべてのサブクラスを分かりやすく定義します。
私はあなたが求めているのではないことを知っていますが、最初のスニペットには生の型が含まれています。つまり、「適切な」ジェネリックコードではありません。下位互換性のためではないということは、これがハードコンパイラエラーであると私の意見です。 –
私はこれがあなたの質問ではないことも知っていますが、プログラムはどちらの場合も同じように動作するので**意味論的な違いはありません。 –