简体   繁体   English

具有未知通用接口类型的Java通用编程

[英]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 : 第一个问题

  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 "?" 考虑到这样的事实,即ClientClass不关心集合的扩展类型是Number的具体类型,我是否应该声明带有“?”的集合? ? If I use the second version I get the following warning: 如果使用第二个版本,则会收到以下警告:

MyCollectionInterface is a raw type. MyCollectionInterface是原始类型。 References to generic type LatticeInterface should be parameterized 泛型类型LatticeInterface的引用应参数化

Second Question : 第二个问题

  1. Why method foo doesn't compile? 为什么方法foo无法编译?

Third question : 第三个问题

  1. It seems that I need to use bar signature to call updateObject method. 看来我需要使用条形码签名来调用updateObject方法。 Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. 无论如何,这种解决方案在尝试分配MyObjectInterface参数时都会产生警告,就像第一个问题一样。 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). 问题是您的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也可以从MyCollectionInterfaceConcreteCollection删除<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM