处理 ArrayStoreException

新手上路,请多包涵
Object[] o = "a;b;c".split(";");
o[0] = 42;

投掷

java.lang.ArrayStoreException: java.lang.Integer

尽管

String[] s = "a;b;c".split(";");
Object[] o = new Object[s.length];
for (int i = 0; i < s.length; i++) {
    o[i] = s[i];
}
o[0] = 42;

没有。

有没有其他方法可以在不创建临时 String[] 数组的情况下处理该异常?

原文由 sp00m 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 613
2 个回答

在 Java 中,数组也是一个 _对象_。

您可以将 子类型 的对象放入 超类型 的变量中。例如,您可以将 String 对象放入 Object 变量中。

不幸的是,Java 中的数组定义不知何故被破坏了。 String[] 被认为是 Object[] 的子类型,但这是 错误 的!有关更详细的解释,请阅读“协变和逆变”,但其本质是:只有当子类型满足超类型的 所有义务 时,类型才应被视为另一种类型的子类型。这意味着,如果你得到一个子类型对象而不是超类型对象,你不应该期望行为与超类型契约相矛盾。

问题是 String[] 只支持 一部分 Object[] 合同。例如,您可以从 Object[] 读取 Object 值。您还可以从 — 读取 Object 值(恰好是 String String[] )。到目前为止,一切都很好。问题出在合同的另一部分。您可以将 任何 Object 放入 Object[] 。但是您不能将 任何 Object 放入 String[] 。因此, String[] 不应被视为 Object[] 的子类型,但 Java 规范说它是。因此我们有这样的后果。

(请注意,泛型类再次出现类似情况,但这次已 正确 解决。 List<String> 不是 List<Object> 的子类型;如果你想拥有一个公共超类型对于这些,您需要 List<?> ,它是只读的。数组也应该如此;但事实并非如此。而且由于向后兼容,现在更改它为时已晚。)

在您的第一个示例中, String.split 函数创建了一个 String[] 对象。您可以将其放入 Object[] 变量中,但对象仍然存在 String[] 。这就是它拒绝 Integer 值的原因。您必须创建一个新的 Objects[] 数组,并复制值。您可以使用 System.arraycopy 函数来复制数据,但您无法避免创建新数组。

原文由 Viliam Búr 发布,翻译遵循 CC BY-SA 3.0 许可协议

不,没有办法避免复制 split 返回的数组。

split 返回的数组实际上是一个 String[] ,Java 允许您将其分配给 Object[] 类型的变量。它仍然是真正的 String[] 但是,所以当您尝试在其中存储 String 以外的其他内容时,您将得到 ArrayStoreException .

背景信息见 4.10.3。 Java 语言规范 中数组类型 的子类型化。

原文由 Jesper 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏