具有未知通用类型接口的Java通用编程 [英] Java generic programming with unknown generic type of interface

查看:145
本文介绍了具有未知通用类型接口的Java通用编程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



假设我有以下接口:

  public interface MyObjectInterface< T extends Number> {} 

实现该接口的对象存储在具有相同泛型类型的泛型集合中:

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





$ b

具体的MyCollectionInterface实例包含几个具有相同泛型参数的MyObjectInterface:

  public class ConcreteCollection< T extends Number>实现
MyCollectionInterface< T> {
List< MyObjectInterface< T>>列表;
public void updateObject(MyObjectInterface< T> o){}

}

现在,我有几个关于如何使用这些通用接口的问题,这些客户类是
(并且必须)不知道具体类型的泛型。



假设我有以下类:

  public class ClientClass { 

私人MyCollectionInterface<?>采集; //第一种可能性
私有MyCollectionInterface集合; //第二种可能性

public ClientClass(MyCollectionInterface<> collection){
this.collection = collection;
}

public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //这不能编译
}
public void foo(MyObjectInterface<?extends Number> o){
this.collection.updateObject(o); //这不会编译

public void bar(MyObjectInterface o){
MyObject b = o; //警告
this.collection.updateObject(o); //此编译但带有警告


code $ $ $ $ $ $ $ $ $ $ $ $ $ $ $第一个问题



  1. 考虑到ClientClass并不关心扩展Number为集合的具体类型,我应该声明有或没有?的收藏?如果使用第二个版本,我会收到以下警告:




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

第二个问题


  1. 为什么foo不会编译?

第三个问题


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

最后一个问题


  1. 我对这个通用接口做了些什么奇怪的事情,我应该重构我的代码?

  2. 我是否真的必须关心所有这些警告?

  3. 如何使用安全性我不知道的类中的通用接口它的具体类型?


解决方案

好的,我玩了一段代码并得出了一个结论。 >

问题在于你的 ConcreteCollection (及其接口 MyCollectionInterface )将 updateObject 方法声明为接收 MyObjectInterface< T> 类型的参数(其中 T extends数字) - 请注意该类型是一个具体的类型(不是通配符)。

现在,在您的客户端类中,您正在接收一个集合并将其存储为 MyCollectionInterface <?>< / code> ,但是传递给 ClientClass 例如:

 新的ClientClass(新的ConcreteCollection< Integer>()); 

这意味着该方法 updateObject 实例只接受类型为 MyCollectionInterface< Integer> 的参数。然后,在方法 foo 您正尝试将 MyObjectInterface<?> 传递给 updateObject ,但因为编译器不知道你的集合接受了哪个泛型类型(它可能是 Integer 就像我的例子中那样,但它也可以是 Double 或任何其他延伸 Number 的类型),它不允许任何对象传递。



长话短说,如果您将引用声明为 MyCollectionInterface<?> ,您将无法调用 updateObject 就可以了。所以你有两个选择:



1)选择一个具体类型并坚持使用它:

  private MyCollectionInterface< Number>采集; 

public ClientClass(MyCollectionInterface< Number> collection){
this.collection = collection;


public void foo(MyObjectInterface< Number> o){
this.collection.updateObject(o); //编译
}

但是,您正在限制可以在构造函数中收到的集合(这可能不是一个坏主意),或者:



2)修改您的界面以接受通配符类型:

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

public class ConcreteCollection< T extends Number>实现MyCollectionInterface< T> {
List< MyObjectInterface< T>>列表;
public void updateObject(MyObjectInterface< ;? extends Number> o){}
}

private MyCollectionInterface<?>采集;

public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}

public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //编译
}

另外,请注意,即使在 2) strong>在执行 updateObject 方法时,您仍然可能遇到同样的问题,除非您声明您的 list 类似于(例如 ArrayList ):

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

在这种情况下,您可以删除< T extends Number> 自 MyCollectionInterface ConcreteCollection T 您的最后一个问题:

<1>可能是的


2)您应该
3)如果您不确定存储在集合中的哪些对象,则不能完全放弃泛型。



对不起,我希望这会有帮助。


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:

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 :

  1. Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:

MyCollectionInterface is a raw type. References to generic type LatticeInterface should be parameterized

Second Question :

  1. Why method foo doesn't compile?

Third question:

  1. It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?

Last questions:

  1. Am I doing something weird with this generic interfaces and I should refactor my code?
  2. Do I really have to care about all these warnings?
  3. How can I use safety a generic interface from a class where I don't know its concrete type?

解决方案

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).

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:

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

This means that the method updateObject of that instance would only accept an argument of type 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.

Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:

1) Pick a concrete type and stick with it:

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:

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):

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.

@Your last questions:

1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.

Sorry for the long answer, hope this helps.

这篇关于具有未知通用类型接口的Java通用编程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆