Frage

In this Java project I'm working on for university, I have a situation where I am currently sending strings through the network successfully using

streamOut = ObjectOutputStream
streamIn = ObjectInputStream

streamOut.writeUTF(msgs.peek());

where msgs is a linked blocking queue, receiving it with

String in = streamIn.readUTF();

however, I would like to use an ObjectInputStream and an ObjectOutputStream. I have initialized them both in the constructor and I flush the ObjectOutputStream after constructing it, I read somewhere you have to do this.

I want to send both Strings and another Object type, call it gameWorld over the network (don't care about efficiency at this point).. however when I do

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

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

it doesn't pick anything up when I send strings over... my friend is working on the same project and he passes around only 1 type of object, one of the subclasses of this object is essentially a string and his version works fine, but he makes a new stream in every iteration of his thread's run loop.

Do I need to do something with the stream to receive different objects which don't have a common ancestor other than Object, do I need to make a new stream every iteration of the run loop or is there just something else completely that I'm missing and the information I've provided isn't sufficient to tell whats wrong?

War es hilfreich?

Lösung

There is a significant difference between writing a String into the stream as primitive data or as an Object. A String instance written by writeObject is written into the stream as a String initially. Future writeObject() calls write references to the string into the stream.

For Example

    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();

Dump last two arrays you will get result like:
writeObject i.e. byteArray1
Binary: -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 F i r s t t S e c o n d t T h i r d

writeUTF i.e. byteArray2
Binary: -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 F i r s t S e c o n d T h i r d

Conclusion: In case of writeObject an extra data (here t)to be streamed whereas in case of writeUTF only the string data to be streamed.

For more: http://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html#writeUTF(java.lang.String)

Andere Tipps

If you want to read the string with readObject() you have to write it with writeObject().

The most important difference is that if you write the String with writeUTF(), then the whole String will always be written into the stream as UTF encoded characters. But if you use writeObject(), then the Object instance of the String is written to the stream. So if you write multiple Strings of the same instance with writeObject(), then the corresponding Strings returned by readObject() will also be guaranteed to be the same Object instance, whereas when you read them with readUTF(), they will not be the same Object instance:

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);

Prints:

true
false

This also results in very different streams: With writeUTF() we get a byte[] of length 18 that includes the UTF characters "test" two times. With writeObject() we get a byte[] of length 16 that includes the UTF characters "test" only once, followed by an integer representing the reference id of the String. So writeObject() will usually result in a smaller file size. This can make a huge difference if a large number of Strings of the same instance are written to the stream (e.g. by calling String.intern()).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top