【问题标题】:Error in Java Generics - Required type: List<MyClass> Provided: List<T>Java 泛型中的错误 - 必需类型:List<MyClass> 提供:List<T>
【发布时间】:2020-07-27 12:02:36
【问题描述】:

我有两个实现接口的类

public class MyClassA implements IClassA {
   // code
}

public class MyClassB implements IClassB {
   // code
}

我有转换这些类的实用函数

public class Util {
    public static List<MyClassB> convertAtoB(List<MyClassA> aClasses) {
             // logic
    }
}

最后,我有一个泛型类

public class GenericClass <D extends IClassA, V extends IClassB> {
    public List<V> someFunc(List<D> in) {
         return Util.convertAtoB(in);   // ERROR HERE
    }
}

错误来了

Required Type: List<MyClassA> 
Provided: List<D>

出了什么问题?

编辑

这是我想要实现的目标

我有许多转换器函数,它们使用某种逻辑将一种类型的列表转换为另一种类型。函数如下所示,在 Util 类中

List<B> convertAtoB(List<A> list) { }
List<C> convertBtoC(List<B> list) { }
List<D> convertCtoD(List<C> list) { }
List<E> convertDtoE(List<D> list) { }
... so on

现在,所有这些都必须异步调用。因此,我将为此目的使用 AyncTask。现在我有两个选择:

选项 1: 创建多个类,每个类都扩展 AsyncTask 并在每个类中调用各自的转换器函数。

class ConvertAtoBAsync extends AsyncTask<List<MyClassA>, Void, List<MyClassB>> {
     public List<MyClassB> doInBackground(List<MyClassA> ...lists) {
           return convertAtoB(lists[0]);
     }
}

class ConvertBtoCAsync extends AsyncTask<List<MyClassB>, Void, List<MyClassC>> {
     public List<MyClassC> doInBackground(List<MyClassB> ...lists) {
           return convertBtoC(lists[0]);
     }
}

.. so on

选项 2:创建一个通用 AsyncTask 类,该类可以根据类类型调用特定类型的转换器

public class ConvertAsync <D extends IClassIn, V extends IClassOut> {
          
        ConvertAsync(Class _class) {  mClass = _class }

        public List<V> someFunc(List<D> in) {
             if(mClass = MyClassA.class)
                   return Util.convertAtoB(in);   // ERROR HERE
             else if(mClass = MyClassB.class)
                   return Util.convertBtoC(in);   // ERROR HERE
             .. so on
        }
    }

我不能使用 Option-2 实现吗?

【问题讨论】:

  • 好吧,你给了错误的参数,编译器对此很不高兴。不知道你为什么会认为未绑定的泛型类型参数DMyClassA是一样的?
  • D IS-A IClassAMyClassA IS-A IClassA,但这并不意味着您可以在需要 MyClassA 的地方传递 DIClassA 可以有许多其他实现。
  • @Kayaman 有一个额外的代码可以知道类型。如果类型是 MyClassA,那么上面的代码会被调用,否则会被调用,等等。这不能做吗?
  • 你需要解释你想要达到的目标。
  • 是的,显然这样做是不安全的,但如果您相信正在使用正确的转换器,您可以转换列表。

标签: java generics


【解决方案1】:

对于 Java 泛型,需要 List&lt;MyClassA&gt;,您必须提供与该元素类型完全相同的 List,例如ArrayList&lt;MyClassA&gt;,而不是例如一个ArrayList&lt;MySubClassA&gt;

此外,在Util 中,您需要参数为List&lt;MyClassA&gt;,而不是使用接口IClassA

因此,当您尝试将 List&lt;D&gt; 传递给您的 Util 方法时,编译器会出于两个原因拒绝:

  • 该方法需要MyClassA元素,而List&lt;D&gt;只能保证接口类型为IClassA的元素还不如来自不同的MyOtherClassA
  • 即使没有这种差异,需要 List&lt;IClassA&gt; 的方法也不会接受 List&lt;MyClassA&gt;,即使考虑到 MyClassA 实现 IClassA 的事实(请参阅下文了解基本原理)。

因此,您应该将Util 方法更改为接受List&lt;? extends IClassA&gt;

基本原理

在方法内部,您可能会尝试将某些内容存储到该列表中。该方法看到List&lt;IClassA&gt; 的类型,因此存储MyOtherClassA 实例看起来完全没问题。但实际上你传入了一个List&lt;MyClassA&gt;,现在这个列表被一个不是MyClassA 类型的元素破坏了。因此,Java 被设计为不允许这样做,编译器将其标记为错误情况是正确的。

通过声明List&lt;? extends IClassA&gt;,您允许使用List&lt;MyClassA&gt; 作为实际参数,同时有效地禁止在方法内部存储到该列表中。

编辑:

您为您的问题添加了更多上下文。不过,我的建议是修改 Util 方法以接受 List&lt;? extends IClassA&gt; 和类似的方法。这应该是使选项 2 起作用的主要因素。

【讨论】:

  • 更多细节在这里也有很多例子/解释:stackoverflow.com/questions/2723397/… - 你的方法convertAtoB(List&lt;MyClassA&gt; aClasses)是不变的,但你希望它是如上所述的“协变”
猜你喜欢
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多