Java:Vararg方法使用显式子类数组调用

Java:Vararg方法使用显式子类数组调用,java,variadic-functions,jls,Java,Variadic Functions,Jls,考虑以下示例,忽略您希望执行此操作的原因: private static class Original { public String getValue() { return "Foo"; } } private static class Wrapper extends Original { private Original orig; public Wrapper(Original orig) { this.orig = or

考虑以下示例,忽略您希望执行此操作的原因:

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())
    });
}
此示例在编译时不提供警告或错误。似乎编译器决定包装器[]包含包装器实例,这实际上意味着这些实例肯定是原始类的实例。这很好

但是,在运行时,包装器[]实例直接传递到方法中。我认为在运行时拆掉这个数组并重新创建一个Original[]的实例是非常明智的,但事实似乎并非如此

这种行为在JLS这样的地方有记录吗?像我这样的普通程序员总是认为我可以操作原始的vararg参数。。。是的,当一个包装器是原件时,那么包装器也是原件。当我意识到这一点时,我也很惊讶

您的包装器是Original的子类型,因为它扩展了原始类

是的,如果被调用的方法试图在传递的数组中存储不是包装器的原始数组,则数组类型之间的子类型关系可能会导致ArrayStoreException。但这并不是在编译时检查的。我的理解是,这正是我们使用ArrayStoreException类型的原因,因为通常在编译时会捕获将错误类型存储到数组中的其他尝试。这里有一个很好的简单例子。该示例还表明,它实际上与varargs或方法调用没有任何关系,它适用于所有数组

Java语言是从版本1开始这样设计的,该版本早在Varags引入之前就已经存在了,顺便说一句。感谢Andy Turner找到Java语言规范JLS参考:它位于:

如果S和T都是引用类型,则S[]>\u 1 T[]iff S>\u 1 T


那么确切的问题是什么呢?这个问题就是为什么Java泛型是不变的,例如List不是List。注意:如果s和T都是引用类型,那么s[]>1T[]iff s>1T。我有点困惑,o的类型是Wrapper[],而不是Original[]传递的参数不应该放在varargs数组中吗?或者对于与参数类型匹配的数组是否有特殊的例外情况?否,@markspace,因为包装器数组不是原始数组,所以不能将其放置在原始数组中。从其他引用类型中,您可能知道对象的运行时类型可能比引用变量的声明类型更精确。这对于数组也是可能的:o的声明类型是array of Original,但运行时类型是array of Wrapper。是的,我太痴迷于这样一个事实,即它发生在vararg上下文中,我没有想到这只是数组的问题。尽管这个问题已经被标记为重复,我还是会将这个答案标记为正确的,因为我认为很高兴找到确切的JLS条款来支持这一点。