我想知道为什么这个转换不起作用:
ArrayList<Song> arrayList =new ArrayList<MediaItem>();
我可能需要补充的是,Song扩展了MediaItem。我认为这种转换应该有效,因为Song有能力存储MediaItem中的所有信息。因此不会丢失任何信息。有人能为我解释一下吗?
有人给我解释吗?
如果该赋值有效,则可以将Song
的另一个子类(与MediaItem
完全无关)的实例放入列表中。因此,这是不允许的。换句话说,Java泛型不是协变的。
这是因为Java中的泛型类型没有协变/逆变。如果你能做这样的任务,就可以做到这一点:
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不希望这种情况发生。因此,它禁止将基于子类的泛型类型分配给基于相应基类的泛型类型。
这不会起作用,因为Java中的泛型不是协变的。也就是说,List<Song>
和List<MediaType>
是两种完全不相关的类型,尽管Song
和MediaType
是相关的。
您的ArrayList
具有不同的具体参数化类型。
在GenericTypes.FAQ101 中阅读更多信息
泛型类型的实例化,其中所有类型参数都是具体类型,而不是通配符。具体参数化类型的示例有
List<String>
、Map<String,Date>
,但不是List<? extends Number>
或Map<String,?>
。
Java泛型中的数组-Java泛型中关于数组的问题是什么?
泛型集合不是协变的。超类型的参数化类型的实例化不被视为子类型的同一参数化类型实例化的超类型。也就是说,
LinkedList<Object>
不是LinkedList<String>
的超类型,因此在期望LinkedList<Object>
的情况下不能使用LinkedList<String>
;同一参数化类型的这两个实例之间没有赋值兼容性等。以下是一个说明差异的例子:
LinkedList<Object> objLst = new LinkedList<String>(); // compile-time error
您可以通过擦除参数化类型和强制转换来实现这一点:
ArrayList<Song> arrayList = (ArrayList<Song>) (ArrayList<?>) new ArrayList<MediaItem>();
这是矛盾的。一方面,声明了Song
s的ArrayList,因此Song
s和从Song
派生的类的对象可以存储在那里。但是,new ArrayList<MediaItem>()
正在创建派生类型的ArrayList,这意味着不能存储直接从Song
派生的其他对象。这两种类型之间的差异是不可调和的。