我有一个ArrayList< Number>我从一个文件中读出来的。但我需要它是一个ArrayList< Integer>。我知道所有的数字都是整数,所以我想我可以这样做:
ArrayList<Number> numbers = new ArrayList<>();
nubers.add( 1 );
// cast the list<Number> to a list<Integer>
ArrayList<Integer> ints = (ArrayList<Integer>)numbers;
ints.add( 2 );
但是,这会导致编译错误。但是,如果我首先将数字转换为Object,则代码运行完美(除了当然不安全的强制转换警告)。
ArrayList<Integer> ints = (ArrayList<Integer>)(Object)numbers;
那么为什么编译器在我的演员阵容中抱怨它是有效演员?
注意:我不是要求解决方案,而是要解释为什么演员阵容不能编译。
奖金问题:
感谢您的解释,但是他们让我想知道为什么this line可以在某些环境中编译?该行的简短摘要:
集合&lt; Bundleable&gt;正在被收集到收藏&lt;?扩展项目&gt;其中Item实现了Bundleable。
答案 0 :(得分:4)
列表的类型信息在运行时不可用,即泛型不可恢复。所以在运行时,演员阵容无论如何都会起作用,就像这样:
ArrayList ints = (ArrayList)numbers;
不用担心。但是如果允许,演员阵容将导致问题,例如你的下面修改过的代码:
ArrayList<Number> numbers = new ArrayList<>();
nubers.add( 1.0 );
// cast the list<Number> to a list<Integer>
ArrayList<Integer> ints = (ArrayList<Integer>)numbers;
Integer x = ints.get(0); // trouble here
基本上,您向double
添加了List<Number>
类型,这完全没问题。如果编译器允许转换,那么它也将在运行时传递。
更进一步,最后一行(评论一行)将失败并显示ClassCastException
,因为您只是尝试将Double
类型分配给Integer
类型。这就是编译器不允许进行此类强制转换的原因。在泛型的情况下,你不应该忽略编译器的未经检查的强制警告(即使这是警告)。
答案 1 :(得分:1)
考虑以下声明:
ArrayList<Number> numbers;
ArrayList
numbers
稍后可以使用扩展Number
类的任何泛型进行实例化,例如:
numbers = new ArrayList<Float>();
现在,您可以通过以下演员看到问题:
ArrayList<Integer> ints = (ArrayList<Integer>)numbers;
但numbers
包含Float
s,而非Integer
s。顺便说一下,将转换为Object
会编译,但会发出警告:
ArrayList<Integer> ints = (ArrayList<Integer>)(Object)numbers;
Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
编译器抱怨未经检查的强制转换,因为它正确地推断出泛型类型可能不匹配。
答案 2 :(得分:0)
请记住,泛型不是真正的类型,它们有类型擦除。因此编译器尝试在编译为字节码之前验证有关使用泛型的方式的许多内容。由于ArrayList<Integer>
不是ArrayList<Number>
的子类型(即使:Integer
是Number
的子类型,或者Number
的列表已满Integer
s),编译器抱怨直接强制转换,因为它可能太危险(不是真正相关的类型)。
在第二种情况下,您以某种方式传递编译器类型检查,因为当然每个类型都是Object
的子类型,并且编译器不能强制执行规则,但他可以警告您关于垂头丧气的情况...