[英]Java generic programming with unknown generic type of interface
I'm using several interfaces with generics types. 我正在使用具有泛型类型的多个接口。 While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
当将它们组合在一起时,当我不得不从一部分代码中使用它们时就遇到了一些问题,这些代码没有意识到泛型参数的具体类型。
Suppose I have the following interface: 假设我有以下界面:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type: 实现该接口的对象以相同的通用类型存储在通用集合中:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter: MyCollectionInterface的具体实例包含相同泛型参数的多个MyObjectInterface:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is (and must be) unaware of the concrete type of generics. 现在,我对如何使用客户端类中的这些泛型接口有几个问题,这些客户端类(并且必须)不了解泛型的具体类型。
Suppose I have the following class: 假设我有以下课程:
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
}
}
First Question :
第一个问题 :
MyCollectionInterface is a raw type.
MyCollectionInterface是原始类型。 References to generic type LatticeInterface should be parameterized
泛型类型LatticeInterface的引用应参数化
Second Question :
第二个问题 :
Third question :
第三个问题 :
Last questions :
最后的问题 :
Ok, I played a bit with your code and reached a conclusion. 好的,我玩了一些您的代码并得出了结论。
The problem is that your ConcreteCollection
(and its interface MyCollectionInterface
) declare the method updateObject
as receiving an argument of type MyObjectInterface<T>
(where T extends Number
) - note that the type is a concrete one (not a wildcard). 问题是您的
ConcreteCollection
(及其接口MyCollectionInterface
)将方法updateObject
声明为接收类型MyObjectInterface<T>
(其中T extends Number
)的参数-请注意,该类型是具体的类型(不是通配符)。
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?>
but the instance that is passed to ClientClass
' constructor will be of a concrete type, for instance: 现在,在您的客户端类中,您将收到一个集合并将其存储为
MyCollectionInterface<?>
但是传递给ClientClass
的构造函数的实例将是一种具体类型,例如:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject
of that instance would only accept an argument of type MyCollectionInterface<Integer>
. 这意味着该实例的
updateObject
方法将仅接受MyCollectionInterface<Integer>
类型的参数。
Then, in method foo
you are trying to pass a MyObjectInterface<?>
to updateObject
, but since the compiler doesn't know which generic type your collection accepts (it could be Integer
like in my example but it could also be Double
or any other type that extends Number
), it won't allow any object to be passed. 然后,在方法
foo
您尝试将MyObjectInterface<?>
传递给updateObject
,但是由于编译器不知道您的集合接受哪种泛型类型(在我的示例中,它可能是Integer
,但也可能是Double
或任何其他类型类型扩展Number
),则不允许传递任何对象 。
Long story short, if you declare your reference as MyCollectionInterface<?>
you won't be able to call updateObject
on it. 长话短说,如果您将引用声明为
MyCollectionInterface<?>
,则将无法对其调用updateObject
。 So you have two choices: 因此,您有两种选择:
1) Pick a concrete type and stick with it: 1)选择一种混凝土类型并坚持下去:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or: 但是随后,您限制了可以在构造函数中接收的集合(这可能不是一个坏主意),或者:
2) Modify your interface to accept a wildcard type: 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
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject
method unless you declare your list
something like this (with ArrayList
for example): 另外,请注意,即使在2)中,除非声明这样的
list
(例如,使用ArrayList
),否则在updateObject
方法的实现中仍然可能遇到相同的问题:
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number>
from MyCollectionInterface
and ConcreteCollection
since T
isn't used anymore. 在这种情况下,由于不再使用
T
也可以从MyCollectionInterface
和ConcreteCollection
删除<T extends Number>
。
@Your last questions: @您的最后一个问题:
1) Probably yes 1)可能是
2) You should 2)你应该
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether. 3)不能,如果您真的不在乎存储在集合中的对象,则应该完全放弃泛型。
Sorry for the long answer, hope this helps. 抱歉,答案很长,希望对您有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.