我正在阅读如何将子类对象分配给父类容器。下面列出了3种情况。对于集合,数组和普通对象。关于如何和& amp;为什么这三个在Java中的处理方式不同。请问下面的场景有简单的解释吗?它们似乎是非常基本的java概念,不知道为什么让我感到困惑。
这会产生编译时错误。
List<Object> objectList = new ArrayList<Integer>();//compile time error
但是,这是允许的
Object object = new Integer(9);
object = 1.2;// no run time error
但这不是吗? (但是,技术上编译器允许,但我们得到运行时错误)
Object objectArr[] = new Integer[1];
objectArr[0] = 1.2;// run time error (Exception in thread "main" java.lang.ArrayStoreException: java.lang.Double)
答案 0 :(得分:2)
如果A是B的子类型,则可以将类型A的内容分配给类型B的变量。一般来说,对于非基本类型,这意味着A必须支持所有的操作B确实。
看看你的例子:
首先:
List<Object> objectList = new ArrayList<Integer>();//compile time error
是的,因为ArrayList<Integer>
不是List<Object>
;您无法为其添加Object
。考虑:
List<Object> l = new ArrayList<Object>();
List<Integer> l2 = new ArrayList<Integer>();
l.add(new Object()); // ok
l2.add(new Object()); // not ok; `List<Integer>` doesn't support this.
因此,您看到List<Integer>
(或ArrayList<Integer>
)不是List<Object>
的子类型 - 因为它不支持所有相同的操作。
下一步:
Object object = new Integer(9);
object = 1.2;// no run time error
在这种情况下,值1.2
会自动装入包装类型Double
(全名java.lang.Double
)。由于这是Object
的子类,因此分配工作正常。变量object
中存储的内容不是原始double
值1.2,而是对包含原始值的Double
对象的引用。
最后:
Object objectArr[] = new Integer[1];
objectArr[0] = 1.2;// run time error (Exception in thread "main" java.lang.ArrayStoreException: java.lang.Double)
这是一个古怪的案例。 Java认为Integer
的数组是Object
数组的子类型,但是通过普通类型理论不会出现这种情况,因为您无法存储Object
(这也不是Integer
}这样的数组。另一方面,Integer
数组至少支持Object
数组所做的所有其他操作 - 您可以检索元素并确保它们是Object
的子类型;你可以查看数组长度;因此,您可以将new Integer[1]
- Integer
数组 - 分配给Object[]
类型的变量。
要使这种形式的子类型工作,Integer
数组需要实现类似于Object
隐式支持的“存储Object[]
元素”操作。但是,由于Integer[]
仅包含Integer
个对象,因此存储操作必须失败 - 因此,如果您尝试存储的内容不是Integer
,则会在运行时获得异常。在您的示例中,您将1.2
存储为自Double
,而不是Integer
。
答案 1 :(得分:0)
ArrayList<Integer>
不是List<Object>
的实现。 ArrayList<Object>
是。
您创建了Integer
并将其分配给Object
变量。您无法将double
分配给Object
,因为double
是基本类型,并且不会从Object
继承。您可以指定Double
。
您创建单个元素的Integer
数组,并将其分配给Object
数组的变量。然后,您尝试为Integer
元素指定一个值,该值不是Integer
。
编辑:
正如达夫曼解释的那样,我对2的回答是不正确的,对象= 1.2;由于boxing,实际上是有效的代码。
进一步解释:
任何Integer
都是Object
,但Object
不一定是Integer
。您可以将Object
添加到List<Object>
,但是只能将Integer
值添加到ArrayList<Integer>
。现在,如果您将ArrayList<Integer>
分配给List<Object>
,那么稍后您可能会尝试将Double
添加到List<Object>
,这对{{1}完全有效}}。但由于您存储了List<Object>
,操作无效,操作将失败。此失败是由于将ArrayList<Integer>
分配给ArrayList<Integer>
的不一致。编译器会保护您免受与编译时错误的不一致。
即使您拥有List<Object>
数组,也不会改变其中包含Object
的事实。并且您尝试为Integer
分配一个值,该值对Integer
无效。
答案 2 :(得分:0)
在第一行中你必须写:
List<? extends Object> objectList = new ArrayList<Integer>();
然后它的工作原理。 ? extends Object
表示List包含扩展Object的元素,例如整数。
如果您使用此处给出的?
运算符,那么您将不再拥有add
方法。因此,您首先需要添加ArrayList
中的所有元素并稍后再分配:
ArrayList<Integer> al = new ArrayList<>();
al.add(3);
...
List<? extends Object> objectList = al;