1

假设我有一个抽象类:

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

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

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 的对象提供,而不是为其创建训练器的特定动物类型。

4

1 回答 1

3

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

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>:显然,您可以使用 调用getStatusanTrainer<Animal>的方法Animal。与上述情况类似。静态类型系统不知道,如果类型不匹配,在运行时你会看到一个异常。

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

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

通配符类型:嗯,这在调用方不起作用 - 没有将其转换Trainer<?>为其他东西。?代表未知的子类型(Animal包括基类本身)。

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

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

于 2013-10-13T10:43:17.243 回答