【问题标题】:Java generic programming with unknown generic type of interface具有未知泛型接口的 Java 泛型编程
【发布时间】:2011-09-04 15:17:44
【问题描述】:

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

假设我有如下界面:

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
    }
}

第一个问题:

  1. 考虑到 ClientClass 不关心扩展 Number 的具体类型是集合,我应该用“还是不带”声明集合? ?如果我使用第二个版本,我会收到以下警告:

MyCollectionInterface 是原始类型。对泛型类型的引用 LatticeInterface 应该被参数化

第二个问题:

  1. 为什么方法 foo 不能编译?

第三题:

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

最后的问题:

  1. 我是否对这个通用接口做了一些奇怪的事情,我应该重构我的代码?
  2. 我真的需要关心所有这些警告吗?
  3. 如何安全地使用我不知道其具体类型的类中的泛型接口?

【问题讨论】:

  • 在方法foo和bar中不应该是MyObjectInterface而不是MyObject吗?
  • 是的,我的错。我修好了它。它是 MyObjectInterface。

标签: java generics interface raw-types


【解决方案1】:

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

问题在于您的ConcreteCollection(及其接口MyCollectionInterface)将updateObject 方法声明为接收MyObjectInterface&lt;T&gt; 类型的参数(其中T extends Number) - 请注意该类型是具体类型(不是通配符)。

现在,在您的客户端类中,您正在接收一个集合并将其存储为MyCollectionInterface&lt;?&gt; 但是传递给ClientClass'构造函数的实例将是一个具体类型,例如:

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

这意味着该实例的方法updateObject 将只接受MyCollectionInterface&lt;Integer&gt; 类型的参数。

然后,在方法@​​987654331@ 中,您尝试将MyObjectInterface&lt;?&gt; 传递给updateObject,但由于编译器不知道您的集合接受哪种泛型类型(可能是Integer,就像我的示例中一样,但是它也可以是Double 或任何其他扩展Number 的类型),它不允许传递任何对象。

长话短说,如果您将参考声明为MyCollectionInterface&lt;?&gt;,您将无法调用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>>();

在这种情况下,您也可以从 MyCollectionInterface 和 ConcreteCollection 中删除 &lt;T extends Number&gt;,因为不再使用 T。

@你最后的问题:

1) 可能是的
2) 你应该
3) 你不能,如果你真的不关心你在集合中存储了哪些对象,你应该完全放弃泛型。

抱歉,回答太长了,希望对您有所帮助。

【讨论】:

  • 问题不在于方法 foo。即使我更改它的签名,问题也在这里: public void updateObject(MyObjectInterface o){} 。即使 T 被声明为 T extends Number,行:this.collection.updateObject(o);不起作用。我什至可以声明 extends Number> 也不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-27
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多