具有 return 列表的方法的通用接口

Generic interface with a method that return a list

我有一个通用接口 (Pack<A extends PackAnimal>),其中一种方法 returns List<A>。今天我发现如果在实现接口的 class 中我忘记指定 class (class XXX implements PackAnimal) return 类型在编译时未检查并失败执行期间

interface PackAnimal {
}
class Buffalo implements PackAnimal {
}

interface LonelyAnimal {
}
class Puma implements LonelyAnimal {
}

interface Pack<A extends PackAnimal> {
    List<A> getMembers();
}

class PumaPack implements Pack {

    @Override
    public List<Puma> getMembers() {
        return null;
    }
}

这是为什么?如果声明中存在任何类型的错误,编译将失败,我该如何强制?

您的列表声明为未知类型。使用 class 类型:

interface Pack<A extends PackAnimal> {
    List<A> getMembers();
}

// won't compile because Puma not within bound
class PumaPack implements Pack<Puma> {
    List<Puma> getMembers() {return null;}
}

// compiles OK
class BuffaloPack implements Pack<Buffalo> {
    List<Buffalo> getMembers() {return null;}
}

但是你无法阻止某人像你的 PumpPack 示例那样编写 raw(缺失类型)实现,但是你会得到一个编译器 warning:

// compile warning
class PumaPack implements Pack {
    List getMembers() {return null;}
}

如果您将编译设置为在出现警告时失败:

javac -Werror ...

那么即使对于原始类型,您也将实现您的目标。

您正在体验使用 Raw Types 的可怕和奇怪的结果。

本质上,如果您错过了 <...> 任何应该出现的地方,编译器会将您的代码视为遗留代码,并且不会做很多它应该做的正常类型检查。大多数编译器尽了最大努力,但在检查过程中留下了漏洞。

interface PackAnimal {
}

class Buffalo implements PackAnimal {
}

interface LonelyAnimal {
}

class Puma implements LonelyAnimal {
}

interface Pack<A extends PackAnimal> {
    // Obviously fine.
    List<A> getMembers();
}

// Raw type so no checking.
class PumaPack implements Pack {

    @Override
    public List<Puma> getMembers() {
        // Raw typed class so Puma isn't checked for PackAnimal super.
        return Arrays.asList(new Puma());
    }
}

class Six {

}

// Properly typed so Raw Types not happening.
class SixPack implements Pack<Six> {

    @Override
    // NOT ALLOWED: Attempt to use incompatible return type!!!
    public List<Six> getMembers() {
        return null;
    }
}