我有一个通用接口(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;
}
}
为什么?如果声明中有任何类型的错误,编译将失败,我怎么强制呢?
答案 0 :(得分: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 ...
然后即使对于原始类型,您也将实现目标。
答案 1 :(得分:1)
您遇到使用Raw Types的可怕而奇怪的结果。
基本上,如果你错过了<...>
任何地方,那么编译器应该将你的代码视为遗留代码,并且不应该进行大量的正常类型检查。 MOst编译器尽力而为,但在检查过程中留下了一些漏洞。
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;
}
}