具有返回列表方法的通用接口

3
我有一个通用接口 (Pack<A extends PackAnimal>),其中只有一个返回类型为 List<A> 的方法。今天我发现,如果在实现该接口的类中忘记指定类 (class XXX implements PackAnimal),则返回类型不会在编译时进行检查,在执行期间会失败。
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;
    }
}

为什么会这样?如果声明中有任何类型的错误,我该如何强制编译失败?
2个回答

2

您的列表声明使用了未知类型。请使用正确的类类型:

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示例那样的原始(缺少类型)实现,但是你会得到一个编译器警告

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

如果你设置编译器在出现警告时失败:
javac -Werror ...

然后,即使是原始类型,您也将实现您的目标。

在我的测试中,它会抛出一个编译错误,而不仅仅是一个警告,使用 Pack<Puma> - 4castle
@4castle 它不应该引起任何错误。这是合法的代码。原始类型已经剥离了所有泛型信息。 - Bohemian
正确,但是使用泛型会导致错误。 - 4castle
@4castle 又是对的(在手机上拇指编码有其局限性)。是的,已编辑。 - Bohemian
我应该更加关注编译警告 xD 但现在我很好奇如何在代码中强制执行那些看似不可能发生的事情。 - Narkha

1
你正在经历使用原始类型的可怕和奇怪结果。
如果你在任何地方漏掉了<...>,编译器会将你的代码视为传统遗留代码,并且不会执行应该执行的大部分正常类型检查。大多数编译器都尽力而为,但这会在检查过程中留下巨大的漏洞。
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;
    }
}

不错,有一个标志可以禁用原始类型。https://dev59.com/IXRB5IYBdhLWcg3wLUu3 - Narkha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接