如何制作这个java通用演员?
public interface IField {
}
class Field implements IField { // package private class
}
public class Form {
private List<Field> fields;
public List<IField> getFields() {
return this.fields;
}
}
return语句抛出一个编译器错误(我知道原因 - 我阅读了泛型教程),但编写这样的代码会非常方便。
如果我将“fields”声明为List,则需要在Form类的其他方法中对Field使用大量的强制转换。
我可以强制该死的编译器弯曲它的规则并编译该返回语句吗?
提前致谢。
答案 0 :(得分:17)
更好的解决方案,IMO,是更改方法的签名以使用有界通配符:
public List<? extends IField> getFields()
这会让调用者将列表中的任何内容视为IField,但它不会让调用者在列表中添加任何内容(没有强制转换或警告),因为他们不知道“真实的“列表类型是。
答案 1 :(得分:12)
碰巧,你可以,因为Java泛型只是嫁接,而不是类型系统的一部分。
你可以做到
return (List<IField>)(Object)this.fields;
因为所有List<T>
个对象都是相同的基础类型。
请记住,这允许任何人在您的列表中放置任何实现IField
的类型,因此如果您的收藏不是只读的,则可能会遇到困难。
答案 2 :(得分:5)
不要这样做。
List<Field>
不是List<IField>
。您可以尝试强制编译器接受(我认为这是不可能的,我希望它不可能),但这会让您陷入困境。编译器将允许用户将从IField派生的AnotherField引入到给定的List中,从而破坏不变量,并打破泛型提供的类型安全性。稍后使用List<Field>
将会中断,因为奇怪元素的提取将无法将隐式强制转换为Field,而您不会期望它发生。
如果您确实需要返回List<IField>
而不是List<Field>
,那么我建议您生成一个填充了相同元素的新列表。如果您可以修改界面,请转到Jon Skeets解决方案。
答案 3 :(得分:2)
如果调用者不需要能够修改列表:
return Collections.<IField>unmodifiableList(this.fields);
答案 4 :(得分:0)
阳光是对的,你可以施展它。
另一个解决方法是仔细检查您确实需要List<Field>
,或者是否可以将内部fields
变量更改为List<IField>
。
只要您只使用IField
接口上列表内容的方法,您就应该能够进行明确的交换。