您可以将enum
s 设为非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
然后查看哪些将被优化掉;所以这个检查对性能没有影响。