【问题标题】:Passing varargs to another method as different type将可变参数作为不同类型传递给另一个方法
【发布时间】:2017-11-02 17:36:37
【问题描述】:

我重构了我的一个类。它应该是可序列化的。它有一个方法 foo,其参数类型为 object varargs。

它可能看起来像:

public class MyClass { 
  public void foo(Object ... param) {
    // do sth
  }
}

重构之后:

public class MyClass implements Serializable { 
  public void foo(Serializable ... param) {
    // do sth
  }
}

现在,还有另一个方法调用 foo 并传递它的对象可变参数。

public void bar(Object ... param) {
  foo(param);
}

此时,我预计将 Object[] 传递给 Serializable[] 时会出错。事实上,如果它是可变参数上的数组,我会的。

但它会将对象可变参数包装到可序列化的数组中。 foo 接收一个具有 1 个元素的可序列化数组,即带有传递的可变参数的对象数组。

为什么会这样? 如何强制这种错误用法在编译时实际抛出错误?

(我在 Java 1.8 中使用 eclipse neon

【问题讨论】:

    标签: java arrays parameters variadic-functions


    【解决方案1】:

    Serializable... 将接受任意数量的参数,只要它们都是可序列化的。

    数组是可序列化的。

    因此,它不会引发编译器错误(请注意,因为 Java 是静态类型的,所以不会是运行时错误)。

    您可以做的是检查foo 的参数是什么,如果param.length == 1 && param[0] instanceof Object[] 则抛出错误。这可能是你能做的最好的了。

    【讨论】:

    • 我认为它有些不同,foo 是用 Object[] 类的一个对象调用的,而数组是可序列化的,所以没有伤害...
    • 但如果在可变参数上使用数组,则会引发编译时错误。对象数组不是预期类型的​​可序列化数组。对象可变参数被自动包装到一个可序列化的数组中以匹配预期的类型。
    • @Gartenzwerg 是的,但请注意...[] 不同。 [] 要求它是一个数组,... 允许您在函数中传递任意数量的参数,例如 f(a, b, c, ..., z)
    • 如果 foo 和 bar 都期望 Serializable varargs。然后 bar 将以 foo 仍接收“平面”可序列化数组的方式传递其可变参数。如果方法需要不同的类型,则 bar 可变参数会自动包装。我不明白为什么会发生后者。还是前者是功能?
    • Object ... 实际上是Object[] 的另一种书写方式,而Object[]Serializable 的子类型。因此,即使Object ... 结构不能作为Serializable ... 可变参数参数逐元素传递,整个Object ... 结构也可以作为Serializable ... 参数的第一个元素传递。
    【解决方案2】:

    通过将参数类型从可变参数更改为数组来解决:

    public void foo(Serializable[] param) { }
    
    // called like this
    foo(new Serializable[] { param1, param2, param3 } );
    
    // or this
    public void bar(Serializable[] param) {
      foo(param);
    }
    

    这样我可以在编译时重新获得类型安全性,而无需额外开销来检查 varargs 参数是否可序列化。

    虽然可序列化数组的手动包装给代码增加了一些噪音,但这似乎是我的情况的最佳折衷方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      • 2015-12-26
      • 2013-07-01
      • 1970-01-01
      相关资源
      最近更新 更多