在Java泛型中的错误 – 所需类型:List 提供的类型:List

huangapple go评论83阅读模式
英文:

Error in Java Generics - Required type: List<MyClass> Provided: List<T>

问题

我有两个实现接口的类

public class MyClassA implements IClassA {
   // 代码
}

public class MyClassB implements IClassB {
   // 代码
}

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

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

最后我有一个泛型类

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

错误信息如下

所需类型List<MyClassA> 
提供的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) { }
... 以此类推

现在所有这些都必须异步调用因此我将使用 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]);
         }
    }
    
    .. 依此类推


**选项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);   // 此处出错
                 else if(mClass == MyClassB.class)
                       return Util.convertBtoC(in);   // 此处出错
                 .. 依此类推
            }
        }


**使用选项2无法实现吗**
英文:

I have two classes implementing interface

public class MyClassA implements IClassA {
// code
}
public class MyClassB implements IClassB {
// code
}

I have Utility function to convert these classes

public class Util {
public static List&lt;MyClassB&gt; convertAtoB(List&lt;MyClassA&gt; aClasses) {
// logic
}
}

Finally, I have a generic class

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

The error is coming as

Required Type: List&lt;MyClassA&gt; 
Provided: List&lt;D&gt;

What is going wrong ?

EDIT

Here is what I want to achieve

I have many converter functions which convert one type of list to another using some logic. Functions look like below and are in Util class

List&lt;B&gt; convertAtoB(List&lt;A&gt; list) { }
List&lt;C&gt; convertBtoC(List&lt;B&gt; list) { }
List&lt;D&gt; convertCtoD(List&lt;C&gt; list) { }
List&lt;E&gt; convertDtoE(List&lt;D&gt; list) { }
... so on

Now, all these have to be invoked Asynchronously. So, I will use AyncTask for this purpose. Now I have two options:

Option-1: Create multiple classes each extending AsyncTask and calling respective converter function in each of them.

class ConvertAtoBAsync extends AsyncTask&lt;List&lt;MyClassA&gt;, Void, List&lt;MyClassB&gt;&gt; {
public List&lt;MyClassB&gt; doInBackground(List&lt;MyClassA&gt; ...lists) {
return convertAtoB(lists[0]);
}
}
class ConvertBtoCAsync extends AsyncTask&lt;List&lt;MyClassB&gt;, Void, List&lt;MyClassC&gt;&gt; {
public List&lt;MyClassC&gt; doInBackground(List&lt;MyClassB&gt; ...lists) {
return convertBtoC(lists[0]);
}
}
.. so on

Option-2: Create a generic AsyncTask class which can invoke a particular type of converter based on class type

public class ConvertAsync &lt;D extends IClassIn, V extends IClassOut&gt; {
ConvertAsync(Class _class) {  mClass = _class }
public List&lt;V&gt; someFunc(List&lt;D&gt; in) {
if(mClass = MyClassA.class)
return Util.convertAtoB(in);   // ERROR HERE
else if(mClass = MyClassB.class)
return Util.convertBtoC(in);   // ERROR HERE
.. so on
}
}

Can I not achieve using Option-2 ?

答案1

得分: 4

使用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生效的主要要素。

英文:

With Java Generics, where a List&lt;MyClassA&gt; is expected, you must provide a List of exactly that element type, e.g. an ArrayList&lt;MyClassA&gt;, not e.g. an ArrayList&lt;MySubClassA&gt;.

Additionally, in Util you require the parameter to be a List&lt;MyClassA&gt;, not using the interface IClassA.

So, when you try to pass List&lt;D&gt; to your Util method, the compiler rejects that for two reasons:

  • The method requires MyClassA elements, and the List&lt;D&gt; only can only guarantee elements of the interface type IClassA which might as well come from a different MyOtherClassA.
  • Even without that difference, a method requiring List&lt;IClassA&gt; will not accept a List&lt;MyClassA&gt;, even given tha fact that MyClassA implements IClassA (see below for rationale).

So you should change the Util method to accept List&lt;? extends IClassA&gt;.

Rationale

Inside the method, you might try to store something into that list. The method sees a type of List&lt;IClassA&gt;, so storing a MyOtherClassA instance would look perfectly okay. But actually you passed in a List&lt;MyClassA&gt;, and now this list gets corrupted with an element not being of type MyClassA. So, Java was designed not to allow that, and the compiler is correct in flagging that as an error situation.

By declaring List&lt;? extends IClassA&gt;, you allow using List&lt;MyClassA&gt; as an actual argument, and at the same time effectively prohibit storing into that list, inside the method.

EDIT:

You added more context to your question. Still, my advice is to modify the Util methods to accept List&lt;? extends IClassA&gt; and similar. That sould be the main element to make Option 2 work.

huangapple
  • 本文由 发表于 2020年7月27日 20:02:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63114920.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定