Отправка того же, но измененного объекта поверх ObjectOutputStream
У меня есть следующий код, который показывает ошибку или недоразумение с моей стороны.
Я отправил тот же список, но был изменен над ObjectOutputStream. Один раз как [0] и другие как [1]. Но когда я его прочитал, я получаю [0] дважды. Я думаю, что это связано с тем, что я отправляю один объект и ObjectOutputStream должен каким-то образом кэшировать их.
Является ли эта работа такой, какой она есть, или мне нужно указать ошибку?
import java.io.*;
import java.net.*;
import java.util.*;
public class OOS {
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
ServerSocket ss = new ServerSocket(12344);
Socket s= ss.accept();
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
List same = new ArrayList();
same.add(0);
oos.writeObject(same);
same.clear();
same.add(1);
oos.writeObject(same);
} catch(Exception e) {
e.printStackTrace();
}
}
});
t1.start();
Socket s = new Socket("localhost", 12344);
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
// outputs [0] as expected
System.out.println(ois.readObject());
// outputs [0], but expected [1]
System.out.println(ois.readObject());
System.exit(0);
}
}
Ответы
Ответ 1
В потоке есть ссылочный граф, поэтому объект, который отправляется дважды, не даст двух объектов на другом конце, вы получите только один. И отправка одного и того же объекта дважды по отдельности даст вам один и тот же экземпляр дважды (каждый с теми же данными - это то, что вы видите).
См. метод reset(), если вы хотите reset график.
Ответ 2
Макс правильный, но вы также можете использовать:
public void writeUnshared(Object obj);
См. комментарий ниже для caveat
Ответ 3
ObjectOutputStream
кэширует экземпляры, которые он отправляет по проводу (не обязательно лучший дизайн tbh). Но в любом случае вам нужно reset выходные потоки между вызовами, если вы планируете использовать его для (повторного) отправки одного и того же экземпляра объекта.
public void reset() throws IOException
Reset будет игнорировать состояние любых объектов, уже записанных в поток. Состояние reset будет таким же, как новый ObjectOutputStream
. Текущая точка в потоке отмечена как reset, поэтому соответствующая ObjectInputStream
будет reset в той же точке. Объекты, ранее записанные в поток, не будут упоминаться как уже находящиеся в потоке. Они снова будут записаны в поток.
Ответ 4
Что вы, возможно, захотите:
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
List same = new ArrayList();
same.add(0);
oos.writeObject(same);
oos.flush(); // flush the stream here
same.clear();
same.add(1);
oos.writeObject(same);
В противном случае один и тот же объект будет дважды сброшен, когда поток будет закрыт или его буфер закончится.
Просто FYI, когда вы десериализуете объекты, скажем o1
и o2
, o1 != o2
.