我正在使用几个带有泛型类型的接口。将它组合在一起时,当我不得不从不知道泛型参数的具体类型的部分代码中使用它时,我遇到了一些问题。
假设我有以下界面:
public interface MyObjectInterface<T extends Number> {}
实现该接口的对象存储在具有相同泛型类型的泛型集合中:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
MyCollectionInterface的具体实例包含相同泛型参数的几个MyObjectInterface:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
现在,我有几个关于如何从客户端类使用这些通用接口的问题 (并且必须)不知道具体类型的泛型。
假设我有以下课程:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
第一个问题:
MyCollectionInterface是原始类型。对泛型类型的引用 LatticeInterface应该参数化
第二个问题:
第三个问题:
上次提问:
答案 0 :(得分:1)
好的,我玩了一些代码并得出结论。
问题是您的ConcreteCollection
(及其接口MyCollectionInterface
)将方法updateObject
声明为接收MyObjectInterface<T>
类型的参数(其中T extends Number
) - 请注意,类型是具体的(不是通配符)。
现在,在您的客户端类中,您收到一个集合并将其存储为MyCollectionInterface<?>
,但传递给ClientClass
'构造函数的实例将是具体类型,例如:
new ClientClass(new ConcreteCollection<Integer>());
这意味着该实例的方法updateObject
只接受MyCollectionInterface<Integer>
类型的参数。
然后,在方法foo
中,您尝试将MyObjectInterface<?>
传递给updateObject
,但由于编译器不知道您的集合接受哪种泛型类型(它可能是{{} 1}}在我的示例中,但它也可能是Integer
或任何其他类型Double
},将不允许传递任何对象。
简而言之,如果您将引用声明为Number
,则无法在其上调用MyCollectionInterface<?>
。所以你有两个选择:
1)选择具体类型并坚持下去:
updateObject
但是你限制了你可以在构造函数中收到的集合(这可能不是一个坏主意),或者:
2)修改您的界面以接受通配符类型:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
另请注意,即使在 2)中,除非您声明public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
这样的内容,否则在updateObject
方法的实现中仍会遇到同样的问题(以list
为例):
ArrayList
在这种情况下,您也可以从List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
和<T extends Number>
移除MyCollectionInterface
,因为ConcreteCollection
已不再使用。
@Your last questions:
1)可能是的 2)你应该 3)你不能,如果你真的不关心你在集合中存储哪些对象,你应该完全抛弃泛型。
很抱歉答案很长,希望这有帮助。