enum
s を非にすることはできpublic
ますが、抽象基本クラスによって強制することはできません。別の方法は、クラスTrainables
に一致する必要がある型パラメーターを追加してジェネリックにすることです。Trainer
これは を内部クラスにすることを強制するものではありませんenum
(それは不可能です) が、準拠するサブクラスの場合、 noRogueTrainer
を作成することはできません。
this
基底クラスまたはインターフェイス内の型に制約を適用することは、トリッキーと不可能の間のどこかにあります。よく知られている例の 1 つは、Comparable
のような実装を防ぐために宣言できないインターフェイスclass Foo implements Comparable<String>
です。
この問題を回避する 1 つの方法は、Trainer
参照をパラメーターにすることです。
public interface Trainables<T extends Trainer<?,? extends Trainables<T>>>
…
public abstract class Trainer
<A extends Animal,
E extends Enum<E> & Trainables<? extends Trainer<A,E>>> {
protected EnumSet<E> completed;
void trainingCompleteImpl(E trainable) {
completed.add(trainable);
}
public static <A extends Animal, T extends Trainer<A,E>,
E extends Enum<E> & Trainables<T>> void trainingComplete(T t, E trainable) {
t.trainingCompleteImpl(trainable);
}
}
public class PoliceDogTrainer
extends Trainer<Dog, PoliceDogTrainer.Tricks> {
public enum Tricks implements Trainables<PoliceDogTrainer> {
FIND_DRUGS, FIND_BOMB, FIND_BODY;
}
}
メソッドは、とpublic static
の適切な組み合わせでのみ呼び出すことができます。このメソッドは、同じパッケージ内の信頼できるサブクラスによって呼び出しおよびオーバーライドできます。これが望ましくない場合は、メソッドのコードをインライン化し、インスタンス メソッドを完全に削除できます。Trainer
Trainables
trainingCompleteImpl
_
別の方法として、 の型パラメーターを作成しTrainer
、パラメーターとthis
実行時に一致させることもできます。
public interface Trainables<T extends Trainer<?,T,? extends Trainables<T>>>
…
public abstract class Trainer
<A extends Animal, T extends Trainer<A,T,E>,
E extends Enum<E> & Trainables<T>> {
protected EnumSet<E> completed;
/** sub-classes should implements this as {@code return this}*/
protected abstract T selfReference();
void trainingComplete(E trainable) {
if(selfReference()!=this) throw new IllegalStateException();
completed.add(trainable);
}
}
public class PoliceDogTrainer
extends Trainer<Dog, PoliceDogTrainer, PoliceDogTrainer.Tricks> {
public enum Tricks implements Trainables<PoliceDogTrainer> {
FIND_DRUGS, FIND_BOMB, FIND_BODY;
}
@Override
protected final PoliceDogTrainer selfReference()
{
return this;
}
}
したがって、非準拠の実装は、簡単に検出できるものとしてTrainer
実装selfReference()
できません。return this;
適合する実装の場合、JVM はselfReference
メソッドをインラインthis==this
化して、最適化されるものを確認します。したがって、このチェックによるパフォーマンスへの影響はありません。