I'm trying to get interface instance depending on what type T is. Place or something else that extends BaseDictionary.
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>
or
Type safety: Unchecked cast from PlaceDataSource to IDictionaryDataSource<T>
if I cast it like above.
Can you explain why do compile error and warning occur?
It will be called here
public static <T extends BaseDictionary> DictionaryElementPickerFragment<T> newInstance(Class<T> clazz, Context cxt){
//somecode here
fragment.setDataSource(DictUtils.getEntityDataSourceInstance(clazz, cxt));
}
I've tried to find answer here and in google but no success.I would appreciate any help. Now I think like this
There is no helper method to work around the problem, because the code is fundamentally wrong.
Thanks in advance.
This more concrete example illustrates your problem which is one of type parameter variance .
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
}
so a List<String>
is not a List<Object>
although it is a List<? extends Object>
List<? extends Object>
.
In your specific instance you can't cast
PlaceDataSource
toIDictionaryDataSource<T>
PlaceDataSource
is an IDictionaryDataSource<Place>
, but the only thing we know about <T>
is that it extends BaseDictionary
which is a super-class of BaseDictionary
.
So you can cast a PlaceDataSource
to
IDictionaryDataSource<Place>
or to IDictionaryDataSource<? super Place>
IDictionaryDataSource<? super Place>
or to IDictionaryDataSource<? extends BaseDictionary>
IDictionaryDataSource<? extends BaseDictionary>
but not to an IDictionaryDataSource<T>
because T
is not guaranteed to be Place
, and doing so would lead to a mismatch between the actual type parameter Place
and the formal type parameter T
.
That is not secure implementation and it is dangerous to cast because ( Place.class.isAssignableFrom(clazz)
saves you here):
T
is a generic type and you're replacing it with definite Place
.
What if I have
public class Home extends BaseDictionary{}
public class HomeDataSource extends BaseDictionaryDataSource<Home>{}
And then I invoke getEntityDataSourceInstance
with Home
class but get PlaceDataSource
which cannot be cast to HomeDataSource
(IDictionaryDataSource) which I expect. So I'll end up having ClassCastException
.
It looks like getEntityDataSourceInstance
should be an instance method in the BaseDictionary
class, not a static method.
A subclass will know which type of DictionaryDataSource
to create.
尝试@SuppressWarnings(“ unchecked”)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.