无法将非泛型子类转换为泛型超类。

4

我正在尝试根据类型T获取接口实例。该类型可以是继承自BaseDictionary的Place或其他内容。

public static <T extends BaseDictionary> IDictionaryDataSource<T> getEntityDataSourceInstance(Class<T> clazz,
        Context cxt) {
    if (Place.class.isAssignableFrom(clazz)) return (IDictionaryDataSource<T>) new PlaceDataSource(cxt);
            //here some other types, same lines

    return null;
}

public abstract class BaseDictionary{}

public class Place extends BaseDictionary{}

public interface IDictionaryDataSource<T extends BaseDictionary>{}

public abstract class BaseDictionaryDataSource<T extends BaseDictionary> implements   IDictionaryDataSource<T>{}

public class PlaceDataSource extends BaseDictionaryDataSource<Place>{}

And I get

Type mismatch: cannot convert from PlaceDataSource to IDictionaryDataSource<T>

或者

Type safety: Unchecked cast from PlaceDataSource to IDictionaryDataSource<T>

如果我像上面那样进行转换。

您能解释为什么会出现编译错误和警告吗?

它将在这里被调用。

public static <T extends BaseDictionary> DictionaryElementPickerFragment<T> newInstance(Class<T> clazz, Context cxt){
     //somecode here
     fragment.setDataSource(DictUtils.getEntityDataSourceInstance(clazz, cxt));
}

我尝试在这里和谷歌上寻找答案,但没有成功。我将非常感激任何帮助。

没有辅助方法可以解决问题,因为代码本质上是错误的。

提前感谢。

4个回答

1
这个更具体的例子阐明了您面临的问题,即类型参数的变化。
void foo(List<String> stringList, Integer anInteger) {
  List<Object> objList = (List<Object>) stringList;
  objList.add(anInteger);  // Violation -- adding an object to a list of strings
                           // could cause someone getting a "String" to get an
                           // Integer stead
}

所以,一个 List<String> 不是一个 List<Object>,尽管它是 List<? extends Object>
在您的特定情况下,您无法将PlaceDataSource转换为IDictionaryDataSource<T>PlaceDataSource是一个IDictionaryDataSource<Place>,但我们只知道<T>扩展了BaseDictionary,而BaseDictionaryPlace的超类。因此,您可以将PlaceDataSource转换为:
1. IDictionaryDataSource<Place> 2. IDictionaryDataSource<? super Place> 3. IDictionaryDataSource<? extends BaseDictionary> 但不能将其转换为IDictionaryDataSource<T>,因为无法保证TPlace,这样做会导致实际类型参数Place和形式类型参数T之间不匹配。

0
那不是安全的实现方式,进行强制类型转换是危险的(Place.class.isAssignableFrom(clazz)可以帮您解决): T 是一个泛型类型,而您正在用确定的 Place 替换它。
如果我有什么其他东西?
public class Home extends BaseDictionary{}
public class HomeDataSource extends BaseDictionaryDataSource<Home>{}

然后我使用Home类调用getEntityDataSourceInstance,但是得到的是PlaceDataSource,无法转换为我期望的HomeDataSource(IDictionaryDataSource)。因此,最终会出现ClassCastException


那么,我该如何根据类变量获取特定的数据源呢?或者说,我应该重写哪些部分呢? - userqwerty1
你无论如何都会收到这个警告。但是 Place.class.isAssignableFrom(clazz) 可以帮助你避免上述情况。你可以使用 @suppressWarnings 注解。 - Tala
嗯,也许我应该使用一些魔法模式或其他什么东西? - userqwerty1
仔细考虑是否需要通用方法。也许您只需要为1或2个类实现它们。另一种解决方案是使用“工厂模式”。这里有一个很好的例子:https://dev59.com/TkfRa4cB1Zd3GeqP-I8_ - Tala

0

看起来getEntityDataSourceInstance应该是BaseDictionary类中的实例方法,而不是静态方法。

子类将知道要创建哪种类型的DictionaryDataSource


BaseDictionary只是一个带有getter和setter的模型,我被告知不要在那里这样做。 - userqwerty1

-3

尝试使用 @SuppressWarnings("unchecked")。


没有人谈论错误。a_vasilkov的代码中没有错误。在Java中,泛型实现非常糟糕,往往抑制这些讨厌的未检查的强制转换警告是唯一的解决方案。 - Frank Olschewski
错误的,弗兰克。如果你没有任何不安全类型警告,你在运行时永远不会有任何ClassCastException。如果你不在意这个问题,就使用原始类型。但是,一半时间使用泛型并忽略你收到的关于真正问题的警告(就像在这种情况下一样;代码确实存在一个错误)是毫无意义的。 - erickson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接