我想我在这里缺少一些基本的东西。任何解释或指向先前提出的问题的指针都将非常有帮助。
import java.util.Arrays;
import java.util.List;
public class St {
public static void bla(Object[] gaga) {
gaga[0] = new Date(); // throws ArrayStoreException
System.out.println(gaga[0]);
}
public static void bla(List<Object> gaga) {
System.out.println(gaga.get(0));
}
public static void main(String[] args) {
String[] nana = { "bla" };
bla(nana); // Works fine
List<String> bla1 = Arrays.asList(args);
bla(bla1); // Wont compile
System.out.println(new String[0] instanceof Object[]); // prints true
System.out.println(nana.getClass().getSuperclass().getSimpleName()); // prints Object
}
}
所以,似乎List<String>
不是List<Object>
的子类,但String[]
是Object[]
的子类。
这是一个有效的假设吗?如果是这样,为什么?如果没有,为什么?
谢谢
Java 数组是协变的,即它们允许Object[] foo = new String[2];
.但这并不意味着它们是子类。 String[]
是 Object
的子类(尽管instanceof
返回 true,String[].class.getSuperclass()
返回 Object
(
是的,你的假设是有效的。如@Bozho所述,数组是协变的,而泛型集合(如泛型 List(不是协变的。
数组中的协方差是有风险的:
String[] strings = new String[] { "a", "b" }
Object[] objects = strings;
objects[0] = new Date(); // <-- Runtime error here
String s = strings[0];
s.substring(5, 3); // ????!! s is not a String
第三行触发运行时异常。如果它没有触发此异常,那么您可以得到一个String
变量 s
,它引用的值不是String
(也不是其子类型(:Date
。
(new String[0] instanceof Object[]) // => true
你是对的。数组类型在 Java 中设计是协变的,但Foo<Sub>
不是Foo<Super>
。
String[]是 Object[] 的子类
正确,请参阅 4.10.3 数组类型之间的子类型:
如果 S 和 T 都是引用类型,则 S[]>1 T[] iff S>1 T。
既然String >1 Object
这么String[] >1 Object[]
也就是说,String[]
是Object[]
的直接亚型
对象>1 对象[]
因此Object > String[]
; String[]
是(间接的?Object
亚型
泛型不存在这种关系,因此List<String> > List<Object>
不正确。
现在,考虑以下简单示例:
import java.util.*;
class G {
interface I {
void f();
}
class C implements I {
public void f() {}
}
void allF(List<I> li) {
for (I i : li) { i.f(); }
}
void x(List<C> lc) {
allF(lc);
}
}
它不编译,因为x
正在使用不是List<I>
的List<C>
调用allF
。为了能够使用List<C>
签名必须稍作更改:
void allF(List<? extends I> li) {
现在它编译了。非正式地说,li
是扩展/实现 I 的某种类型的List
。所以List<C>
可以分配给List<? extends I>
.您可以使用此类列表执行的操作是有限的。本质上,您可以读取/访问它,但不能write/modify
它。