为什么类型转换在Java中不起作用

时间:2014-01-05 23:35:48

标签: java generics arraylist casting covariance

我想知道为什么这种转换不起作用:

ArrayList<Song> arrayList =new ArrayList<MediaItem>();

我可能要补充说Song扩展了MediaItem。 我认为这种转换应该有效,因为Song能够存储MediaItem的所有信息。所以没有信息丢失。 有没有人对我有解释?

5 个答案:

答案 0 :(得分:4)

  

有人对我有解释吗?

如果该分配有效,那么您可以将另一个Song子类的实例(与MediaItem完全无关)放入列表中。因此不允许这样做。换句话说, Java泛型不是covariant

答案 1 :(得分:2)

这不起作用,因为Java中的泛型不协变。含义List<Song>List<MediaType>是两种完全不相关的类型,即使SongMediaType相关。

答案 2 :(得分:2)

这是因为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不希望这种情况发生。因此,它禁止基于子类将泛型类型分配给基于相应基类的泛型类型。

答案 3 :(得分:2)

您的ArrayList具有不同的具体参数化类型

GenericTypes.FAQ101

中详细了解此信息
  

泛型类型的实例化,其中所有类型参数都是具体类型而不是通配符。   具体参数化类型的示例包括List<String>Map<String,Date>,但不是List<? extends Number>Map<String,?>

Arrays in Java Generics - What are the issues regarding arrays in Java Generics?

  

通用集合不协变。超类型的参数化类型的实例化不被认为是子类型的相同参数化类型的实例化的超类型。也就是说,LinkedList<Object>不是LinkedList<String>的超类型,因此在预期LinkedList<String>的情况下不能使用LinkedList<Object>;这两个相同参数化类型的实例之间没有赋值兼容性等。

     

这是一个说明差异的例子:

     

LinkedList<Object> objLst = new LinkedList<String>(); // compile-time error

您可以通过删除参数化类型和强制转换来实现此目的:

ArrayList<Song> arrayList = (ArrayList<Song>) (ArrayList<?>) new ArrayList<MediaItem>();

答案 4 :(得分:0)

这是矛盾的。一方面,声明了Song s的ArrayList,因此Song s和从Song派生的类的对象可以存储在那里。但是,new ArrayList<MediaItem>()正在创建派生类型的ArrayList,这意味着不能存储直接从Song 派生的其他对象。这些类型之间的差异是不可调和的。