【问题标题】:Object[] array to String[] using Serialization使用序列化将 Object[] 数组转换为 String[]
【发布时间】:2014-02-27 22:55:51
【问题描述】:

ObjectInputStream 的 readObject() 方法返回 Object 并且需要为 casted 以匹配 type。如果我serialize 和array of String,我会得到array of Objects 还是Array of Strings。我在下面试过这个。 String[] arr = (String[]) objArr; 在一般情况下失败。 但是在Serialization 之后,当我将从readObject() 返回的Object 转换为String[] 时,我没有得到任何Exception。那返回的是什么? readObject() 的方法签名是 public final Object readObject() throws IOException, ClassNotFoundException 表示它返回对象。 为什么将其转换为 String[] 在这里有效,但在更一般的情况下(如下所示)它会失败。

public class UpcastDownCast {

        public static void main(String[] args) throws IOException, ClassNotFoundException {

                   //the below three lines give runtime Exception
            Object[] objArr = {new String("hello"), new String("world")};
            String[] arr = (String[]) objArr;
            System.out.println(Arrays.toString(arr));


            String[] arrV={new String("Car"), new String("Bike")};


            FileOutputStream of= new FileOutputStream("file.ser");
            ObjectOutputStream oos=new ObjectOutputStream(of);
            oos.writeObject(arrV);


            FileInputStream fi = new FileInputStream("file.ser");
            ObjectInputStream ois= new ObjectInputStream(fi);
            String[] t2=   (String[]) ois.readObject();
            System.out.println("after "+ Arrays.toString(t2));


        }
    }

【问题讨论】:

  • 因为实例被转换为与它们起源相同的类型,就像人类一样,它们是公民。

标签: java arrays string serialization objectinputstream


【解决方案1】:

在您的第一个示例中,您创建了一个Object[] 类型的对象,并将其转换为String[]。由于Object[] 没有扩展String[],所以转换失败。这就像想把香蕉投给苹果。香蕉不是苹果,所以演员表失败了。

在序列化示例中,String[] 类型的对象被序列化,然后反序列化。序列化机制包括写入对象的类型,然后是它的状态。反序列化时,它会重新创建一个相同类型的对象 (String[]),然后用读取的状态填充它。因此,该对象是String[],并且将String[] 转换为String[] 可以正常工作。

【讨论】:

    【解决方案2】:

    Array variance 允许您将String[] 视为Object[] 没有问题,然后您可以毫无问题地回退:

    Object[] x = new String[] { "x", "y", "z" };
    System.out.println(x.getClass()); // Prints class [Ljava.lang.String;
    String[] y = (String[]) x; // No exception
    

    这与您的序列化案例相对应 - 序列化只是保留数组的类型(正如我所期望的那样 - 否则它会很糟糕)。序列化在这里实际上是一个红鲱鱼 - 完全不使用序列化很容易演示相同的问题。

    代码开头的转换问题是由于您的数组初始化,它创建了一个Object[] 实例,而不是String[] 实例:

    Object[] x = { "x", "y", "z" };
    System.out.println(x.getClass()); // Prints class [Ljava.lang.Object;
    String[] y = (String[]) x; // ClassCastException
    

    第一行相当于:

    Object[] x = new Object[] { "x", "y", "z" };
    

    要创建的数组的类型不是从数组的元素中推断出来的,而是从正在声明的变量的类型中推断出来的。 (不幸的是,据我所知,JLS 中并没有非常明确地规定......但这绝对是它的工作方式。)

    如果您将用于序列化的变量的声明更改为:

    Object[] arrV={new String("Car"), new String("Bike")};
    

    ...那么当你转换反序列化的结果时你会看到同样的异常。

    (另请注意,无需到处调用 String(String) 构造函数 - 只需 { "Car", "Bike" } 即可。)


    关于数组方差的一点要注意:这是在执行时检查的。例如:

    Object[] x = { "x", "y", "z" };
    x[0] = new Object(); // This is fine, because the array really is an Object[]
    
    Object[] y = new String[] { "x", "y", "z" };
    y[0] = new Object(); // This compiles, but throws an ArrayStoreException
                         // because the array is really a String[]
    

    【讨论】:

    • "要创建的数组类型不是从数组的元素中推断出来的,而是从正在声明的变量的类型中推断出来的。"你能详细说明你的意思吗?
    • @user1988876:你的声明等同于Object[] o = new Object[] {"a", "b"},而不是Object[] o = new String[] {"a", "b"}
    • @user1988876:我的意思是即使你已经指定了字符串元素,在数组初始化器中,它仍然在创建Object[] 类型的对象,因为这就是变量 (objArr) 的方式已初始化 - 是否明确使用 new String[]。请参阅我的两个示例,它们仅在x的声明类型上有所不同。
    • @JBNizet:很好的说明 - 我会将其编辑到我的答案中。 (不知道为什么它被否决了,但没关系。)
    • 我投了赞成票,因为它不值得投反对票,而且提供了有价值的信息。
    【解决方案3】:

    Java 数组有点奇怪。 String[] 可转换为 Object[]。它仍然是 String[] 的运行时类型,所以如果你转换然后尝试在其中放入一个非 String 对象,你会得到一个运行时错误。

    序列化考虑了运行时类型,所以它保存了你给它一个String[]的事实,即使“arr”变量的类型是“Object[]”,它也持有一个“String[] "

    ois.readObject() 在这种情况下将重建一个 String[]。

    【讨论】:

      【解决方案4】:

      案例 1:

      Object[] objArr = {new String("hello"), new String("world")};
      String[] arr = (String[]) objArr;
      
      • 您可以将所有内容放入objArr,而不仅仅是字符串。
      • 字符串数组只能包含字符串

      这就是为什么将String[] 转换为Object[] 是非法。

      案例 2:

      String[] strArr = {new String("hello"), new String("world")};
      Object[] arr = strArr; // you do not even need to cast
      
      • 每个字符串都是一个对象

      所以你从Object[] 数组中得到的所有东西都是一个对象,这就是它合法的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-24
        • 2022-01-17
        • 2018-07-16
        • 1970-01-01
        • 2010-11-08
        • 2013-05-24
        相关资源
        最近更新 更多