英文:
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<MyClassB> convertAtoB(List<MyClassA> aClasses) {
// logic
}
}
Finally, I have a generic class
public class GenericClass <D extends IClassA, V extends IClassB> {
public List<V> someFunc(List<D> in) {
return Util.convertAtoB(in); // ERROR HERE
}
}
The error is coming as
Required Type: List<MyClassA>
Provided: List<D>
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<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
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<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
Option-2: Create a generic AsyncTask class which can invoke a particular type of converter based on class type
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
}
}
Can I not achieve using Option-2 ?
答案1
得分: 4
使用Java泛型,在需要 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生效的主要要素。
英文:
With Java Generics, where a List<MyClassA>
is expected, you must provide a List
of exactly that element type, e.g. an ArrayList<MyClassA>
, not e.g. an ArrayList<MySubClassA>
.
Additionally, in Util
you require the parameter to be a List<MyClassA>
, not using the interface IClassA
.
So, when you try to pass List<D>
to your Util
method, the compiler rejects that for two reasons:
- The method requires
MyClassA
elements, and theList<D>
only can only guarantee elements of the interface typeIClassA
which might as well come from a differentMyOtherClassA
. - Even without that difference, a method requiring
List<IClassA>
will not accept aList<MyClassA>
, even given tha fact thatMyClassA
implementsIClassA
(see below for rationale).
So you should change the Util
method to accept List<? extends IClassA>
.
Rationale
Inside the method, you might try to store something into that list. The method sees a type of List<IClassA>
, so storing a MyOtherClassA
instance would look perfectly okay. But actually you passed in a List<MyClassA>
, 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<? extends IClassA>
, you allow using List<MyClassA>
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<? extends IClassA>
and similar. That sould be the main element to make Option 2 work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论