【发布时间】:2017-03-20 02:44:33
【问题描述】:
可行时
Number number = new Integer("");
为什么不这样?
List<Number> list = new LinkedList<Integer>();
【问题讨论】:
-
我敢肯定你能找到六个骗子。
可行时
Number number = new Integer("");
为什么不这样?
List<Number> list = new LinkedList<Integer>();
【问题讨论】:
这可能会有所帮助:
http://www.ibm.com/developerworks/java/library/j-jtp01255.html
基本上,由于您声明了一个数字列表,API 将允许您在其中输入任何类型的数字,包括不是整数的数字。
【讨论】:
你快到了。 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 是“some kind of Number”,但不能保证匹配“a specific kind of Number”,例如, Double.
【讨论】:
我总是觉得举例说明为什么不允许这样做很有用。考虑以下代码:
// 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
基本上,如果泛型是协变的,那么它们将毫无价值,因为您无法保证泛型会将列表限制为假定的内容(这是它们的全部存在的理由,毕竟)。正如您所期望的那样,any 列表可以传递到 List<Object> 变量中,然后任何对象都可以合法地放入其中。
如上所示,您可以使用通配符来表示它可以是某种类型的数字列表;但是您不能将元素添加到列表中,因为不能保证元素的类型正确。
【讨论】:
考虑到这是可行的,可能会让您对正在发生的事情有所了解:
List<? extends Number> list = new LinkedList<Integer>();
extends 表示等式两边的泛型类型之间的关系。
【讨论】:
C++ 模板和 Java 泛型之间是有区别的。 Java 的泛型是编译器时的类型检查。对于 C++,C++ 编译器会根据模板编译一个全新的类。在 Java 的情况下,它只是编译时类型检查,并且在生成的字节码中删除了此信息。因此泛型不是协变的(它们不知道谁是父级,谁是子级)。
【讨论】:
这个问题超出了 Java 泛型的任何细节。它更多地是关于一般的子类型化。
Number 只有 read 方法,而 List 也有 write 方法。假设 Number 也有 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 中的方法。
另一个例子,方形和矩形。哪个应该是超类型,哪个应该是子类型?这真的取决于他们有什么方法。
根据我们的数学训练,我们“直觉地”认为这些对象是不可变的。甚至 List 感觉 就像一个不可变的对象序列。 “子类型”通常等同于数学中的“子集”。
在命令式编程中并非如此,这会产生很多心理冲突。
【讨论】:
List<? extends Number> list = new LinkedList<Integer>();
【讨论】: