考虑以下示例,忽略了这样做的原因:
private static class Original {
public String getValue() {
return "Foo";
}
}
private static class Wrapper extends Original {
private Original orig;
public Wrapper(Original orig) {
this.orig = orig;
}
@Override
public String getValue() {
return orig.getValue();
}
}
public static void test(Original... o) {
if (o != null && o.length > 0) {
for (int i = 0; i < o.length; i++) {
if (o[i] instanceof Wrapper) {
o[i] = ((Wrapper) o[i]).orig; // Throws java.lang.ArrayStoreException at runtime
}
}
}
}
public static void main(String[] args){
test(new Wrapper[] { // Explicitly create an array of subclass type
new Wrapper(new Original())
});
}
此示例在编译时不给出警告或错误。似乎编译器决定Wrapper[]
包含Wrapper
个实例,这实际上意味着这些绝对是Original
类的实例。很好。
但是,在运行时,Wrapper[]
实例直接 传递到方法中。我曾经认为,删除该数组并在运行时重新创建Original[]
的实例足够聪明,但是似乎并非如此。
是否曾经在某处(例如JLS)记录过此行为?像我这样的普通程序员总是会假设我可以像对待Original...
一样操作Original[]
的vararg参数。
答案 0 :(得分:1)
是的,当一个Wrapper
是一个Original
时,一个Wrapper[]
也是一个Original[]
(当我意识到这一点时,我也感到惊讶)。
您的Wrapper
是Original
的子类型,因为它消除了Original
类。
是的,如果被调用的方法试图将不是ArrayStoreException
的{{1}}存储到传递的数组中,则数组类型之间的子类型关系可能会引起Original
。但这不是在编译时检查的。据我了解,这正是我们拥有Wrapper
类型的原因,因为通常在编译时会捕获将错误类型存储到数组中的其他尝试。 the documentation of ArrayStoreException
中有一个很好的简短示例。该示例还说明,它与所有数组的varargs或方法调用实际上无关。
Java语言是从版本1(很早就引入varargs,BTW)开始设计的。感谢Andy Turner查找Java语言规范(JLS)参考:它在section 4.10.3 Subtyping among Array Types中:
如果S和T都是引用类型,则S []> _1 T []如果S> _1 T。