Чтобы ответить на ваш первый вопрос:
Вам необходимо использовать ObjectInputStream.readObject
для десериализации.Вы не можете читать отдельные поля из потока *.
fromClient = new ObjectInputStream(socket.getInputStream());
Object myObject = fromClient.readObject();
Не забудьте очистить поток вывода при записи!
Второй вопрос немного сложнее.Механизм сериализации записывает идентификатор потока в поток, за которым следуют данные сериализованного объекта.Когда он десериализуется, он прочитает идентификатор класса и попытается загрузить этот класс (если он еще не загружен).Затем он создаст экземпляр объекта с помощью конструктора no-arg и вызовет закрытый метод readObject(ObjectInputStream)
.Да, верно, он вызывает закрытый метод извне класса.Сериализация Java является особенной.
Если класс не может быть найден (то есть, если он не находится на пути к классам), то будет выдано исключение;в противном случае вы получите полностью десериализованный объект правильного типа, при условии, что другие ошибки не найдены.
Например, предположим, что у вас есть следующие классы:
class Server {
public static void main(String[] args) {
// Set up an OutputStream sink, e.g. writing to a socket (not shown)
...
ObjectOutputStream out = new ObjectOutputStream(sink);
out.writeObject(new Data("data goes here"));
out.flush();
out.close();
}
}
class Client {
public static void main(String[] args) {
// Set up an InputStream source (not shown)
...
ObjectInputStream in = new ObjectInputStream(source);
Data d = (Data)in.readObject();
System.out.println(d.getData());
}
}
class Data implements java.io.Serializable {
private String data;
public Data(String d) {
data = d;
}
public String getData() {
return data;
}
}
Теперь предположим, что вы поставили теКлассы на три банки (один класс на банку): server.jar, client.jar и data.jar.Если вы выполните следующие команды, то все должно работать:
java -cp server.jar:data.jar Server
java -cp client.jar:data.jar Client
Но если вы сделаете это:
java -cp server.jar:data.jar Server
java -cp client.jar Client
, тогда вы получите ClassNotFoundException
, потому что клиент не 'Не знаю, как найти класс Data
.
Короче говоря: сам класс не записывается в поток.Если десериализация завершится успешно, вы получите доступ к объекту, как если бы он был создан локально, но вам придется понизить результат readObject
до ожидаемого типа.
Существует некоторая сложность в отношении управления версиями, которую япока проигнорировали.Посмотрите на serialVersionUID
и как бороться с изменениями в сериализуемых классах, если существует вероятность того, что управление версиями будет проблемой.
* Не совсем верно.Вы можете вызвать readFields
внутри метода readObject
сериализуемого объекта (или readResolve
), но вы не можете вызвать его извне механизма десериализации.Имеет ли это смысл?Это немного сложно объяснить.