2012-09-11 44 views
30
Object[] o = "a;b;c".split(";"); 
o[0] = 42; 

抛出与ArrayStoreException信息处理

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[]阵列?

+4

Object [] o =“a; b; c”.split(“;”); o [0] = 42;这里你要创建一个字符串数组,而Object [] o = new Object [s.length];是一个对象数组。 – Satya

回答

53

在Java阵列也是对象

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

不幸的是,Java中的数组定义被破坏了。 String[]被认为是Object[]的子类型,但这是错误!为了了解“协变和逆变”更详细的解释,但本质上它是:A型应该算是另一种类型的子类型只有在满足亚型所有义务的超类型的。这意味着,如果你得到的是一个子类型对象而不是一个超类型对象,那么你就不应该期待与超类型合约相矛盾的行为。

问题是,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函数来复制数据,但无法避免创建新阵列。

+0

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html#FAQ102 –

6

没有,有没有办法避免复制数组split回报。

的数组split回报实际上是一个String[],和Java允许您指定,要Object[]类型的变量。但它仍然是一个String[],因此当您尝试在其中存储除String之外的其他内容时,您将获得一个ArrayStoreException

有关背景信息,请参阅4.10.3. Subtyping among Array Types在Java语言规范。

0

当然还有其他的选择,比如你实现你自己的split方法,它直接返回一个Object数组。我不确定究竟是什么使临时String数组困扰你?

顺便说一句,你可以使用几行System.arrayCopy,而不是实施自己的循环复制的数组元素缩短代码:

System.arrayCopy(s, 0, o, 0, s.length); 
-1

如果它没有必要用一个“分裂” ..然后你可以避免复制...