问题
I`m wondering why this conversion is not working:
ArrayList<Song> arrayList =new ArrayList<MediaItem>();
I may have to add that Song extends MediaItem. I think this conversion should work because Song has the ability to store all the information form MediaItem. So no information is lost. Does anyone have an explanation for me?
回答1:
This is because generic types in Java have no covariance/contravariance. If you could do the assignment like that, one would be able to do this:
ArrayList<MediaItem> mediaItems = new ArrayList<MediaItem>(); // Legal
ArrayList<Song> songs = mediaItems; // Illegal; let's imagine it's legal for a moment
// Note that songs and mediaItems are the same list
songs.add(new Song()); // This is perfectly fine
Song firstSong = songs.get(0); // That's OK - it's a Song
mediaItems.add(new Video()); // This is perfectly fine, too
// However, the addition above also modifies songs: remember, it's the same list.
// Now let's get the last object from songs
Song lastSong = songs.get(1); // Wait, that's not a Song, it's a Video!!!
Java does not want this to happen. Hence, it prohibits assignments of generic types based on subclasses to generic types based on the corresponding base classes.
回答2:
Does anyone have an explanation for me?
If that assignment were valid, then you could put an instance of another subclass of Song
(completely unrelated to MediaItem
) into the list. Hence it's not allowed. In other words, Java generics are not covariant.
回答3:
This won't work because generics in Java not covariant. Meaning, List<Song>
and List<MediaType>
are two totally unrelated types, even though Song
and MediaType
are related.
回答4:
Your ArrayList
s have different concrete parameterized type .
Read more about this in GenericTypes.FAQ101
An instantiation of a generic type where all type arguments are concrete types rather than wildcards. Examples of concrete parameterized types are
List<String>
,Map<String,Date>
, but notList<? extends Number>
orMap<String,?>
.
Arrays in Java Generics - What are the issues regarding arrays in Java Generics?
Generic collections are not covariant. An instantiation of a parameterized type for a supertype is not considered a supertype of an instantiation of the same parameterized type for a subtype. That is, a
LinkedList<Object>
is not a supertype ofLinkedList<String>
and consequently aLinkedList<String>
cannot be used where aLinkedList<Object>
is expected; there is no assignment compatibility between those two instantiations of the same parameterized type, etc.Here is an example that illustrates the difference:
LinkedList<Object> objLst = new LinkedList<String>(); // compile-time error
You can achieve this by erasing parametrized type and casting:
ArrayList<Song> arrayList = (ArrayList<Song>) (ArrayList<?>) new ArrayList<MediaItem>();
回答5:
It's contradictory. On one hand, an ArrayList of Song
s is declared, so Song
s and objects of classes derived from Song
can be stored there. However, new ArrayList<MediaItem>()
is creating an ArrayList of the derived type, meaning that other objects derived directly from Song
can't be stored. The difference between the types is irreconcilable.
来源:https://stackoverflow.com/questions/20940652/why-does-a-type-conversion-not-work-in-java