何时可行
Number number = new Integer("");
为什么不呢?
List<Number> list = new LinkedList<Integer>();
答案 0 :(得分:7)
这可能有所帮助:
http://www.ibm.com/developerworks/java/library/j-jtp01255.html
基本上,由于您声明了Number列表,因此API允许您在其中输入任何类型的Number,包括不是Integer的Number。
答案 1 :(得分:7)
你快到了。 Java中的类型参数既不是隐式covariant也不是逆变;也就是说,它们是不变的。您可以使用bounded wildcards来编写几乎相同的声明:
final List<? extends Number> number = new LinkedList<Integer>();
鉴于您的列表在此处开始为空,并且您打算插入项目,您正在寻找协方差:即,您可以插入Number
类型的任何项目,例如Integer
。请注意,LinkedList
构造函数打算将内容锁定以仅允许插入Integer
类型,并且绑定引用number
不再确切知道实际的Number
类型列表可以容纳。正如您所期望的那样,您可以从number
获得协变读数:
final Number n = number.get(0);
但是你不能插入Number
,因为引用的类型不能保证要插入的元素和列表本身的声明类型之间的正确协方差。
number.add(new Integer(0));
该表达式无法编译; Integer
是“{em>某种 Number
”,但不能保证匹配“ Number
的特定种类”这可能是,Double
。
答案 2 :(得分:4)
我总是觉得举例说明为什么不允许这样做很有用。请考虑以下代码:
// Create and initialise a list of integers
List<Integer> myIntegerList = new ArrayList<Integer>();
myIntegerList.add(1);
// Some other stuff, possibly passing the list through method calls
List<Number> numbers = myIntegerList;
numbers.add(2.0d); // Legal, since this is a list of double
// And at some point later...
myIntegerList.get(1); // throws ClassCastException because element is a Double
基本上,如果泛型是协变的,那么它们就没有任何价值,因为你无法保证泛型会将列表限制为所谓的内容(这是他们的整个 raison d'etre ,毕竟)。您期望工作的方式,任何列表可以传递到List<Object>
变量,然后任何对象都可以合法地放在其中。
如上所示,您可以使用通配符来表示它可以是某种类型的数字列表;但是你不能在列表中添加元素,因为无法保证元素的类型正确。
答案 3 :(得分:1)
考虑一下这个有用的事实,可能会让你知道发生了什么:
List<? extends Number> list = new LinkedList<Integer>();
extends
表示等式两边的泛型类型之间的关系。
答案 4 :(得分:1)
C ++模板和Java泛型之间存在差异。 Java的泛型是编译器时间类型检查。对于C ++,C ++编译器根据模板编译一个全新的类。在Java的情况下,它只是编译时间类型检查,并且在生成的字节代码上删除此信息。因此,泛型不是协变的(他们不知道谁是父母,谁是孩子)。
答案 5 :(得分:1)
这个问题超出了Java Generics的任何细节。它更多的是关于一般的子类型。
Number只有 read 方法,而List也有 write 方法。假设一分钟数字写方法
class Number
void set(Number that){...}
Integer i = 1;
Float f = 2.5;
Number n = i;
n.set(f); // same as i.set(f), that's trouble
在此实验中,Integer不再是Number的子类型,因为它不支持Number中的方法。
另一个例子,Square和Rectangle。哪一个应该是超类型,哪一个应该是子类型?这实际上取决于他们有什么方法。
通过我们的数学训练,我们“直观地”将这些对象视为不可变的。甚至List 感觉就像一个不可变的对象序列。 “子类型”通常等同于数学中的“子集”。
在命令式编程中并非如此,并且会产生许多精神冲突。
答案 6 :(得分:0)
List<? extends Number> list = new LinkedList<Integer>();