java.lang.ArrayStoreException:将不正确类型的值分配给 Object [] 数组时 [重复]

Posted

技术标签:

【中文标题】java.lang.ArrayStoreException:将不正确类型的值分配给 Object [] 数组时 [重复]【英文标题】:java.lang.ArrayStoreException: when assigning value with incorrect type to Object[] array [duplicate] 【发布时间】:2018-11-19 23:31:35 【问题描述】:

我来自 C 背景。我不能在foo() 中将Object 添加到Object[],这对我来说没有意义。

我希望函数 foo 中的代码在运行时工作,但在我尝试执行 strings[0].toLowerCase(); 时在 main() 中失败,因为 strings[0] 中的对象不是 String,但实际上是 @987654330 @ 没有toLowerCase()。在一天结束时,我将一个指针存储到一个指针数组中,objects[0] = other 行不应该是无效的。很明显,我对 java 的理解是错误的(但我现在还是个新手)。

class Main 

    static void foo(Object[] objects, Object other) 
        objects[0] = other;
    
    public static void main(String[] args) 
        String[] strings =  "stringValue" ;
        foo(strings, new StringBuilder());
    

编辑:谢谢大家的回答。感谢@Andy Turner,我在谷歌上搜索了“数组的java协方差”,并遇到了讨论这种行为的this。诀窍是编译器和运行时处理代码的方式非常不同。编译器可以处理代码,运行时不行。

【问题讨论】:

您将StringBuilder 的实例分配给String 的数组。这是不正确的。 我将Object 分配给另一个Object。这应该是有效的。所有函数foo 说的是“获取此对象引用并将其添加到此数组中”。我同意,稍后,当我将其转换回 String[] 并尝试在 StringBuilder 对象上调用 String 方法时,它应该会失败。 @s5s stringsString[],而不是 Object[]。如果你调用foo(...),它会向上转换为Object[],但是一旦你尝试将一些不是String 的东西存储到这个数组中,你就会得到一个ArrayStoreException ArrayStoreException 非常适合这个。 这是一个很好的例子,说明为什么数组的协方差是一个设计错误。 【参考方案1】:

来自ArrayStoreException的documentation:

抛出以指示已尝试将错误类型的对象存储到对象数组中。例如,以下代码生成 ArrayStoreException:

Object x[] = new String[3];
x[0] = new Integer(0);

仅仅因为您将String[] 传递给需要Object[] 的方法并不意味着它实际上是Object[]。因为您创建了String[],所以您只能向其中添加String 的实例,而您正在尝试添加StringBuilder,这没有任何意义。

请注意,如果将String[] 的类型更改为Object[],它不会引发异常:

public static void main(String[] args) 
    Object[] strings =  "stringValue" ;
    foo(strings, new StringBuilder()); // Perfectly fine

【讨论】:

那么JVM是在做运行时类型检查吗?我希望objects[0] = new StringBuilder() 不会失败,但稍后,如果我尝试在strings[0] 上调用String 方法,我会崩溃,因为指针实际上并未指向String 我对 JVM 的了解还不够多,无法告诉您,但听起来确实如此。鉴于您来自 C 背景,Java 的不同之处在于它通常不会让用户犯这些错误。 检查在the language specification of the simple assignment operator 中描述:“Java 编译器可能能够在编译时证明数组组件的类型为 TC(例如,TC 可能是最终的)。但是如果 Java 编译器无法在编译时证明数组组件的类型为 TC,则必须在运行时执行检查以确保类 RC 与数组的实际类型 SC 的赋值兼容(第 5.2 节)组件。”【参考方案2】:

在运行时评估您的字符串数组实际上是在尝试分配不同的类型。你会是一个ArrayStoreException,它清楚地表明了

抛出表示试图存储错误的 将对象类型转换为对象数组。例如,以下 代码生成一个 ArrayStoreException:

Object x[] = new String[3];
 x[0] = new Integer(0);

接受对象类型作为参数甚至方法/函数的返回值通常不是一个好习惯。它们可能是多态接口,但 Object 处于最高抽象级别,不适合此目的。

【讨论】:

是的,很少需要使用 Object 作为类型参数。我只是不明白为什么在运行时我会遇到将void 指针存储到void 指针数组中的问题。同样,正如我所说,如果我稍后发生崩溃,我会理解,我将这个 void 指针转换为 String 并尝试在演员表上调用 String 方法,如果我这样做会发生@ 987654328@.【参考方案3】:

您正在尝试将对象“StringBuilder”添加到对象“String”的数组中。在某些情况下,如果您要分配 StringBuilder 值,这实际上可能有效,但我不会对此表示担忧,因为我自己从未使用过它。 这是一个很好的阅读:https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html

通常 Java 会为您处理指针,这很难搞砸。

希望能帮到你:)

【讨论】:

我对我使用的类型并不特别在意——我使用 StringBuilder 只是因为。假设我有String[] 并尝试分配class Foo 的实例。 我不懂 C 但在 Java 中你需要严格控制数组中的对象类型。对象有一个名为 Object 的超类,因此您可能会尝试拥有一个“对象”数组并向其中添加一个类。

以上是关于java.lang.ArrayStoreException:将不正确类型的值分配给 Object [] 数组时 [重复]的主要内容,如果未能解决你的问题,请参考以下文章