您可以将enums 设为非public,但这不能由抽象基类强制执行。另一种方法是Trainables通过添加必须与类匹配的类型参数来实现泛型Trainer。这并不强制将enum其作为内部类(这是不可能的),但是对于符合要求的子类,RogueTrainer则不能创建 no 。
对基类或接口内部的类型实施约束this介于棘手和不可能之间。一个众所周知的例子是Comparable接口,它不能以阻止实现的方式声明,如class Foo implements Comparable<String>.
规避此问题的一种方法是将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然后查看哪些将被优化掉;所以这个检查对性能没有影响。