Java:使用显式子类数组调用的 Vararg 方法
Java: Vararg method called with explicit subclass array
考虑以下示例,忽略人们想要这样做的原因:
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
class 的实例。这很好。
但是,在运行时,Wrapper[]
实例直接 传递到方法中。我认为在运行时拆除这个数组并重新创建 Original[]
的实例会很聪明,但似乎并非如此。
是否曾在某处(如 JLS)记录过此行为?像我这样的普通程序员总是假设我可以操纵 Original...
的可变参数,就好像它是 Original[]
.
是的,当Wrapper
是Original
时,Wrapper[]
也是Original[]
(当我意识到这一点时,我也很惊讶)。
您的 Wrapper
是 Original
的子类型,因为它扩展了 Original
class.
是的,如果调用的方法试图将不是 Wrapper
的 Original
存储到传递的大批。但这在编译时没有检查。据我了解,这正是我们拥有 ArrayStoreException
类型的原因,因为通常其他将错误类型存储到数组中的尝试会在编译时被捕获。 the documentation of ArrayStoreException
中有一个很好的简短示例。该示例还表明它与可变参数或方法调用没有任何关系,它适用于所有数组。
Java 语言从版本 1 开始就是以这种方式设计的(顺便说一句,在引入可变参数之前很久)。感谢 Andy Turner 找到 Java 语言规范 (JLS) 参考:它位于 section 4.10.3 Subtyping among Array Types:
If S and T are both reference types, then S[] >_1 T[] iff S >_1 T.
考虑以下示例,忽略人们想要这样做的原因:
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
class 的实例。这很好。
但是,在运行时,Wrapper[]
实例直接 传递到方法中。我认为在运行时拆除这个数组并重新创建 Original[]
的实例会很聪明,但似乎并非如此。
是否曾在某处(如 JLS)记录过此行为?像我这样的普通程序员总是假设我可以操纵 Original...
的可变参数,就好像它是 Original[]
.
是的,当Wrapper
是Original
时,Wrapper[]
也是Original[]
(当我意识到这一点时,我也很惊讶)。
您的 Wrapper
是 Original
的子类型,因为它扩展了 Original
class.
是的,如果调用的方法试图将不是 Wrapper
的 Original
存储到传递的大批。但这在编译时没有检查。据我了解,这正是我们拥有 ArrayStoreException
类型的原因,因为通常其他将错误类型存储到数组中的尝试会在编译时被捕获。 the documentation of ArrayStoreException
中有一个很好的简短示例。该示例还表明它与可变参数或方法调用没有任何关系,它适用于所有数组。
Java 语言从版本 1 开始就是以这种方式设计的(顺便说一句,在引入可变参数之前很久)。感谢 Andy Turner 找到 Java 语言规范 (JLS) 参考:它位于 section 4.10.3 Subtyping among Array Types:
If S and T are both reference types, then S[] >_1 T[] iff S >_1 T.