Java 泛型中的错误 - 必需类型:提供的列表<MyClass>:列表<T>



我有两个类实现接口

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

我可以不使用选项2吗

对于Java Generics,在需要List<MyClassA>的情况下,必须提供与该元素类型完全相同的List,例如ArrayList<MyClassA>,而不是ArrayList<MySubClassA>

此外,在Util中,您需要参数为List<MyClassA>,而不是使用接口IClassA

因此,当您试图将List<D>传递给Util方法时,编译器会拒绝,原因有两个:

  • 该方法需要MyClassA元素,而List<D>只能保证接口类型为IClassA的元素,这些元素可能来自不同的MyOtherClassA
  • 即使没有这种差异,需要List<IClassA>的方法也不会接受List<MyClassA>,即使MyClassA实现了IClassA(基本原理见下文(

因此您应该更改Util方法以接受List<? extends IClassA>

基本原理

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

通过声明List<? extends IClassA>,可以使用List<MyClassA>作为实际参数,同时有效地禁止在方法内部存储到该列表中。

编辑:

你为你的问题添加了更多的上下文。不过,我的建议是修改Util方法以接受List<? extends IClassA>和类似的方法。这将是使方案2发挥作用的主要因素。

最新更新