2011-09-04 57 views
2

我正在使用几个带有泛型类型的接口。在将它们组合在一起时,我不得不从一部分不知道泛型参数的具体类型的代码中使用它们时遇到一些问题。具有未知通用类型接口的Java通用编程

假设我有以下接口:

public interface MyObjectInterface<T extends Number> {} 

执行该interfaceare存储在一个泛型集合有相同的通用类型的对象:MyCollectionInterface的

public interface MyCollectioninterface<T extends Number> { 
    public void updateObject(MyObjectInterface<T> o); 
} 

具体事例举行的几个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 
    } 
} 

首先问

  1. 考虑一个事实,即ClientClass不关心其具体类型扩展号码是收藏,我应该申报收集有无“?” ?如果使用第二个版本,我会收到以下警告:

MyCollectionInterface是一种原始类型。引用泛型类型 LatticeInterface应该是参数

第二个问题

  1. 为什么foo方法无法编译?

第三个问题

  1. 看来,我需要用吧签名调用updateObject方法。无论如何,这个解决方案在尝试分配MyObjectInterface参数时会产生警告,就像第一个问题一样。我可以删除此警告吗?

最后的问题

  1. 我在做一些奇怪这个通用接口,我应该重构我的代码?我真的不得不关心所有这些警告吗?
  2. 如何从一个不知道具体类型的类使用安全通用接口?
+0

什么是MyObject? –

+0

不应该在'foo'和'bar'方法中使用'MyObjectInterface'而不是'MyObject'吗? – guardianpt

+0

是的,我的错。我修好了它。它是MyObjectInterface。 – Heisenbug

回答

1

好吧,我玩了一下你的代码,并得出了一个结论。

的问题是,你的ConcreteCollection(及其接口MyCollectionInterface)声明所述方法updateObject作为接收MyObjectInterface<T>型(其中T extends Number)的参数 - 注意,类型是一个具体的一个(不是通配符)。现在

,在您的客户端类您收到集合,把它作为MyCollectionInterface<?>传递给ClientClass'的构造将是一个具体类型的实例,例如:

new ClientClass(new ConcreteCollection<Integer>()); 

这意味着该实例的方法updateObject将只接受MyCollectionInterface<Integer>类型的参数。

然后,在方法foo你试图传递一个MyObjectInterface<?>updateObject,但是因为编译器不知道哪个泛型类型您的收藏接受(可能是Integer就像在我的例子,但它也可能是Double或任何其他类型,延伸Number),它将不允许任何对象被传递。长话短说,如果你声明你的参考文献是MyCollectionInterface<?>,你将无法对其打电话updateObject。所以,你有两个选择:

1)选择一个具体类型,并坚持下去:

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 
} 

此外,请注意,即使在2)你仍然可能会遇到同样的问题,在你执行updateObject方法,除非你宣布你list像这样(与ArrayList为例):

List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>(); 

在哪你可以从MyCollectionInterfaceConcreteCollection中删除<T extends Number>,因为T不再使用。

@Your最后的问题:

1)可能是
2)你应该
3)你不能,如果你真的不关心你的收集存储的对象,你应该抛弃一般的泛型。

对不起,很长的答案,希望这会有所帮助。

+0

问题不是foo的方法。即使我改变它的签名问题在这里:public void updateObject(MyObjectInterface o){} 。即使T声明为T extends Number,行:this.collection.updateObject(o);不起作用。我甚至可以声明<?扩展Number>并且它也不起作用。 – Heisenbug

+0

用新的答案编辑。 – guardianpt