У меня есть:
class MyClass extends MyClass2 implements Serializable {
//...
}
В MyClass2 есть свойство, которое нельзя сериализовать. Как я могу сериализовать (и десериализовать) этот объект?
Исправление: MyClass2 - это, конечно, не интерфейс, а класс.
MyClass2 можно изменить. Однако было бы лучше не делать этого, так как я строю на нем и он может быть изменен другими.




MyClass2 - это просто интерфейс, поэтому технически он не имеет свойств, только методы. При этом, если у вас есть переменные экземпляра, которые сами по себе не сериализуемы, единственный известный мне способ обойти это - объявить эти поля временными.
бывший:
private transient Foo foo;
Когда вы объявляете временное поле, оно будет проигнорировано в процессе сериализации и десериализации. Имейте в виду, что когда вы десериализуете объект с временным полем, значение этого поля всегда будет значением по умолчанию (обычно нулевым).
Обратите внимание, что вы также можете переопределить метод readResolve () вашего класса, чтобы инициализировать временные поля на основе другого состояния системы.
Вам нужно будет внедрить writeObject() и readObject() и выполнить сериализацию / десериализацию этих полей вручную. См. Подробности на странице javadoc для java.io.Serializable. В Эффективная Java Джоша Блоха также есть несколько хороших глав, посвященных реализации надежной и безопасной сериализации.
Вы можете начать с изучения ключевого слова преходящий, которое помечает поля как не являющиеся частью постоянного состояния объекта.
Если вы можете изменить MyClass2, самый простой способ решить эту проблему - объявить свойство временным.
Это не отвечает на вопрос - в вопросе указано, что MyClass2 содержит свойство, которое не может быть сериализовано, и в идеале MyClass2 не следует изменять.
Вы правы, я не очень внимательно прочитал вопрос, когда ответил на него. Я изменил ответ.
XStream - отличная библиотека для быстрой сериализации Java в XML для любого объекта, независимо от того, является ли он сериализуемым или нет. Даже если целевой формат XML вам не подходит, вы можете использовать исходный код, чтобы узнать, как это сделать.
привет, не могли бы вы объяснить, как использовать XStream с несериализуемым объектом?
Документация говорит сама за себя, руководство начинается с классов, которые не реализуют Serializable, и показывает, как их сериализовать: x-stream.github.io/tutorial.html
Зависит от того, почему этот член MyClass2 не сериализуем.
Если есть веская причина, по которой MyClass2 не может быть представлен в сериализованной форме, то, скорее всего, та же причина применима к MyClass, поскольку это подкласс.
Можно написать настраиваемую сериализованную форму для MyClass путем реализации readObject и writeObject таким образом, чтобы состояние данных экземпляра MyClass2 в MyClass можно было соответствующим образом воссоздать из сериализованных данных. Это было бы подходящим вариантом, если API MyClass2 исправлен и вы не можете добавить Serializable.
Но сначала вы должны выяснить, почему MyClass2 не сериализуемый, и, возможно, изменить его.
Как заметил кто-то другой, глава 11 книги Джоша Блоха Эффективная Java является незаменимым ресурсом по сериализации Java.
Пара моментов из этой главы, имеющих отношение к вашему вопросу:
Ниже я написал небольшой пример, иллюстрирующий это.
class MyClass extends MyClass2 implements Serializable{
public MyClass(int quantity) {
setNonSerializableProperty(new NonSerializableClass(quantity));
}
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
// note, here we don't need out.defaultWriteObject(); because
// MyClass has no other state to serialize
out.writeInt(super.getNonSerializableProperty().getQuantity());
}
private void readObject(java.io.ObjectInputStream in)
throws IOException {
// note, here we don't need in.defaultReadObject();
// because MyClass has no other state to deserialize
super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
}
}
/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {
/* this property must be gettable/settable by MyClass. It cannot be final, therefore. */
private NonSerializableClass nonSerializableProperty;
public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
this.nonSerializableProperty = nonSerializableProperty;
}
public NonSerializableClass getNonSerializableProperty() {
return nonSerializableProperty;
}
}
class NonSerializableClass{
private final int quantity;
public NonSerializableClass(int quantity){
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
}
Ой, я надеялся на какую-то аннотацию вроде @NonSerialization: - /
Полезный подход для сериализации экземпляров несериализуемых классов (или, по крайней мере, подклассов) известен как последовательный прокси. По сути, вы реализуете writeReplace для возврата экземпляра совершенно другого сериализуемого класса, который реализует readResolve для возврата копии исходного объекта. Я написал пример сериализации java.awt.BasicStroke на Usenet
Выскочило несколько возможностей, и я возобновляю их здесь:
Если возможно, несерийные части можно установить как временные.
private transient SomeClass myClz;
В противном случае вы можете использовать Крио. Kryo - это быстрая и эффективная платформа сериализации графов объектов для Java (например, для сериализации JAVA java.awt.Color требуется 170 байт, Kryo только 4 байта), которая может сериализовать также несериализуемые объекты. Kryo также может выполнять автоматическое глубокое и поверхностное копирование / клонирование. Это прямое копирование от объекта к объекту, а не object->bytes->object.
Вот пример того, как использовать kryo
Kryo kryo = new Kryo();
// #### Store to disk...
Output output = new Output(new FileOutputStream("file.bin"));
SomeClass someObject = ...
kryo.writeObject(output, someObject);
output.close();
// ### Restore from disk...
Input input = new Input(new FileInputStream("file.bin"));
SomeClass someObject = kryo.readObject(input, SomeClass.class);
input.close();
Сериализованные объекты также можно сжимать, зарегистрировав точный сериализатор:
kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));
Можете ли вы изменить MyClass2 или нет? Нужно ли сохранять значение несериализуемого свойства посредством сериализации? От этого зависит правильный подход.