可以说我有一个抽象类:

public abstract class Trainer<T extends Animal>{
...
}


我希望所有的孩子班级都有一个通用的方法来检查训练员对给定动物的训练状态。所以在我的Trainer定义中:

public abstract class Trainer<T extends Animal>{
   public double getStatus(Animal a){
   ...
   }
}


这样,任何人都可以查询培训师,而不论其具体类型是什么。但是,要使各个培训人员负责报告自己的状态,我要求各个培训人员实施一个internalGetStatus方法,然后希望我的getStatus方法调用。所以我现在正在做的是:

public abstract class Trainer<T extends Animal>{
   protected abstract internalGetStatus(T theAnimal);
   public double getStatus(Animal a){
     return internalGetStatus((T) a);
   }
}


问题是,当然,return internalGetStatus((T) a);涉及未经检查的类型转换,它抛出我想避免的警告。

有没有办法做到这一点?

由于某些设计限制超出了我的控制范围,因此当查询特定动物的状态时,将其作为父类Animal的对象提供,而不是为其创建教练的特定动物类型。

最佳答案

这取决于类的使用方式。但是,您对此没有多说。让我们从以下代码开始:

abstract class Animal { }

final class Lion extends Animal { }

abstract class Trainer<T extends Animal> {
    public abstract double getStatus(T animal);
}

final class LionTrainer extends Trainer<Lion> {
    public double getStatus(Lion lion) {
        return 4.2;
    }
}


您提到getStatus方法的调用方不知道动物的类型。这意味着他没有使用Trainer<Lion>,而是使用原始类型,Trainer<Animal>或通配符类型。让我们看一下这三种情况。

原始类型:类型参数与原始类型无关。您可以使用getStatus调用方法Animal。只要TrainerAnimal的子类型匹配,此方法就起作用。否则,您将在运行时看到ClassCastException

void raw(Trainer trainer, Animal animal) {
    trainer.getStatus(animal);
}


Trainer<Animal>:显然,您可以使用getStatus调用Trainer<Animal>的方法Animal。与上述情况类似。静态类型系统不知道,并且在运行时,如果类型不匹配,您将看到异常。

void base(Trainer<Animal> trainer, Animal animal) {
    trainer.getStatus(animal);
}


请注意,可以将LionTrainer传递给此方法(使用强制转换),因为在运行时Trainer<Animal>Trainer<Lion>之间没有区别。

通配符类型:嗯,这在调用者端不起作用-如果不将Trainer<?>强制转换为其他内容。 ?代表Animal的未知子类型(包括基类本身)。

void wildcard(Trainer<?> trainer, Animal animal) {
    trainer.getStatus(animal); // ERROR
}


结果是,如果框架使用原始类型或基本类型,则应该没有问题。否则,将强制类型转换添加到代码中,使用注释取消警告,并记录为什么决定采用这种方式,会更简单。

09-30 15:27