2014-02-27 100 views
0

ObjectInputStreamreadObject()方法返回对象,并且需要将casted更改为适当的type。如果我serializearray of String,我得到array of ObjectsArray of Strings。我在下面试过。在一般情况下,String[] arr = (String[]) objArr;失败。 但Serialization后,当我投返回从readObject()String[],我没有得到任何Exception。那么返回的是什么? readObject()的方法签名是 public final Object readObject() throws IOException, ClassNotFoundException它指示它返回Object。 为什么将它转换为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)); 


     } 
    } 
+0

因为实例投射到他们是公民的人类相同的类型。 –

回答

1

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[] 
+0

“要创建的数组类型不是从数组的元素中推断出来的,而是从正在声明的变量的类型中推断出来的。你能详细说明你的意思吗? –

+1

@ user1988876:您的语句等同于Object [] o = new Object [] {“a”,“b”}',而不是Object [] o = new String [] {“a”,“b” }' –

+0

@ user1988876:我的意思是,即使你已经在数组初始值设定项中指定了字符串元素,它仍然会创建一个Object []类型的对象,因为这是变量('objArr')的初始化方式 - 是它明确地使用'新的String []'或不。看看我的两个例子,它们在'x'的声明类型中不同* only *。 –

1

Java数组有点奇怪。一个String []可转换为Object []。它仍然具有String []的运行时类型,因此,如果您投射然后尝试将非String对象放入其中,则会出现运行时错误。

序列化将运行时类型考虑在内,因此尽管“arr”变量的类型为“Object []”,但它保存了String []的事实,它保存着一个“String [ ]“

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

2

在你的第一个例子,你创建Object[]类型的对象,并将其转换为String[]。由于Object[]不延伸String[],投射失败。这就像是想把香蕉扔给苹果。香蕉不是苹果,所以演员失败了。

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

+0

谢谢,有道理。 –

0

案例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[]阵列得到的是一个对象,那为什么它的法律

相关问题