writeUTF(String s)与writeObject(String s)的区别

3
在我正在为大学进行的Java项目中,我遇到了一个情况,目前我正在成功地通过网络发送字符串,使用的是


streamOut = ObjectOutputStream
streamIn = ObjectInputStream

streamOut.writeUTF(msgs.peek());

其中,msgs是一个链式阻塞队列,可以通过以下方式进行接收:

String in = streamIn.readUTF();

然而,我想使用 ObjectInputStream 和 ObjectOutputStream。我已经在构造函数中初始化了它们,并在构造后刷新了 ObjectOutputStream,我从某个地方读到你必须这样做。

我想通过网络发送字符串和另一个对象类型(称为 gameWorld),但目前不关心效率... 然而当我这样做时

streamOut.writeObject("mad cuz i'm bad");

Object in = streamIn.readObject(); 
if(in instanceof String) String inS = (String) in;

当我发送字符串时,它没有接收到任何内容...我的朋友正在处理同一个项目,他只传递一种类型的对象,这个对象的子类之一本质上是一个字符串,他的版本可以正常工作,但是他在每次迭代线程的运行循环时都会创建一个新的流。

我是否需要对流进行某些操作以接收没有除Object之外的共同祖先的不同对象?我是否需要在运行循环的每次迭代中创建一个新的流,还是有其他我错过的东西,我提供的信息不足以确定问题所在?


你的意思是在 Object in = streamIn.readObject(); 这行代码之后,in 是 null 吗? - smajlo
3个回答

4

将String作为原始数据或对象写入流中,存在显着的差异。由writeObject写入的String实例最初被写入流中作为一个String。未来的writeObject()调用会将对该字符串的引用写入流中。

例如

    ByteArrayOutputStream baos1=new ByteArrayOutputStream();
    oos1=new ObjectOutputStream(baos1);
    baos2=new ByteArrayOutputStream();
    ObjectOutputStream oos2=new ObjectOutputStream(baos2);
    String testString="First";
    oos1.writeObject(testString);
    oos2.writeUTF(testString);
    testString="Second";
    oos1.writeObject(testString);
    oos2.writeUTF(testString);
    testString="Third";
    oos1.writeObject(testString);
    oos2.writeUTF(testString);
    oos1.flush();
    oos2.flush();
    byte[] byteArray1=baos1.toByteArray();
    byte[] byteArray2=baos2.toByteArray();

转储最后两个数组,您将得到如下结果:
writeObject即byteArray1
二进制:-84 -19 0 5 116 0 5 70 105 114 115 116 116 0 6 83 101 99 111 110 100 116 0 5 84 104 105 114 100
ASCII码:-T- t First t Second t Third

writeUTF即byteArray2
二进制:-84 -19 0 5 119 22 0 5 70 105 114 115 116 0 6 83 101 99 111 110 100 0 5 84 104 105 114 100
ASCII码:-T- w First Second Third

结论:在使用writeObject时,会流出额外的数据(这里是t),而在使用writeUTF时,只会流出字符串数据。

更多信息请参见:http://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeUTF(java.lang.String)


太棒了,搞定了。谢谢你,我不知道引用的事情,这就是让我失败的原因,也是为什么我的朋友每次都要创建一个新的流才能工作的原因。 - boris dzhelali
这两个十六进制转储之间没有区别。您已经两次发布了相同的内容。第一个与给定的ASCII呈现不一致。 - user207421

0
最重要的区别在于,如果您使用writeUTF()编写字符串,则整个字符串将始终作为UTF编码字符写入流中。但是,如果您使用writeObject(),则会将字符串的对象实例写入流中。因此,如果您使用writeObject()编写同一实例的多个字符串,则由readObject()返回的相应字符串也保证是相同的对象实例,而当您使用readUTF()读取它们时,它们将不是相同的对象实例:
ByteArrayOutputStream bytes1 = new ByteArrayOutputStream();
ObjectOutputStream out1 = new ObjectOutputStream(bytes1);
ByteArrayOutputStream bytes2 = new ByteArrayOutputStream();
ObjectOutputStream out2 = new ObjectOutputStream(bytes2);

String writeString = "test";
out1.writeObject(writeString);
out1.writeObject(writeString);

out2.writeUTF(writeString);
out2.writeUTF(writeString);

out1.flush();
out2.flush();

ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(bytes1.toByteArray()));
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bytes2.toByteArray()));

String readString1 = (String) in1.readObject();
String readString2 = (String) in1.readObject();

System.out.println(readString1 == readString2);

readString1 = (String) in2.readUTF();
readString2 = (String) in2.readUTF();

System.out.println(readString1 == readString2);

输出:

true
false

这也导致非常不同的流:使用writeUTF(),我们得到一个长度为18的byte[],其中包括两次UTF字符“test”。使用writeObject(),我们得到一个长度为16的byte[],其中仅包括一次UTF字符“test”,后跟表示String引用ID的整数。因此,writeObject()通常会导致更小的文件大小。如果将大量相同实例的字符串写入流中(例如通过调用String.intern()),这可能会产生巨大的差异。

0

如果你想使用readObject()读取字符串,你必须使用writeObject()来写入它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接