代码之家  ›  专栏  ›  技术社区  ›  Jai

用显式子类数组调用的java:vararg方法[duplicate]

  •  0
  • Jai  · 技术社区  · 6 年前

    这个问题已经有了答案:

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

    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 上课。这很好。

    但是,在运行时, 包装器[] 实例是 直接地 传递到方法中。我以为拆掉这个数组并重新创建 Original[] 在运行时,但似乎不是这样。

    这种行为有没有记录在案(比如jls)?像我这样的普通程序员总是假设我可以操作 Original... 好像是一个 原件[] 是的。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Anonymous    6 年前

    是的,当 Wrapper 是一个 Original ,然后也是 Wrapper[] 是一个 Original[] (当我意识到这一点时,我也很惊讶)。

    你的 包装 原件 因为它把 原件 上课。

    是的,数组类型之间的子类型关系可能导致 ArrayStoreException 如果被调用的方法试图存储 原件 那不是 包装 进入传递的数组。但这在编译时没有检查。据我所知,这正是我们拥有 阵列存储异常 类型,因为通常在编译时会捕获将错误类型存储到数组中的其他尝试。中有一个很好的简短示例 the documentation of ArrayStoreException 是的。该示例还演示了它实际上与varargs或方法调用没有任何关系,它的for all数组。

    Java语言是从版本1(在引入varargs之前很久)开始设计的。感谢andy turner找到了java语言规范(jls)参考:它在 section 4.10.3 Subtyping among Array Types 以下内容:

    如果s和t都是引用类型,则s[]>_1 t[]iff s>_1 t。