Java не может сериализовать объекты, которые содержат TreeMaps с компараторами
В качестве задания (для курса ООП от Uni) у меня есть довольно большой проект: школьный реестр, где ученики могут видеть свои оценки, учителя могут добавлять оценки и так далее.
"Базовый" класс - это синглтон, который содержит все используемые классы (Java), такие как массив пользователей, классы (как в школьных классах) и TreeMap, который связывает классы и преподавателей с курсами.
Я хочу сериализовать этот базовый класс (Центральный), чтобы сохранить измененные данные. Проблема в том, что я получаю это исключение
java.io.NotSerializableException: liceu.Central$1
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:440)
at java.util.TreeMap.writeObject(TreeMap.java:2265)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1495)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
at liceu.Main.main(Main.java:31)
Все мои классы реализуют Serializable, и у них нет переходных или статических полей (за исключением синглтона, который имеет переменную экземпляра и метод getInstance в качестве статики).
Поскольку было бы достаточно много кода для публикации (и я рискнул бы аннулировать свое назначение, опубликовав его перед отправкой), я попытался доказать концепцию, пытаясь изолировать ошибку.
public class Central implements Serializable
{
private ArrayList <User> users;
private ArrayList <Class> classess;
private TreeMap <Course, TreeMap <Class, Professor>> reunite;
private static Central instance = null;
private Central()
{
users = new ArrayList<>();
classess = new ArrayList<>();
reunite = new TreeMap<>(new Comparator<Student>(){
@Override
public int compare(Student e1, Student e2)
{
return e1.getName().compareTo(e2.getName());
}
});
}
}
Если я оставлю только первые 2 ArrayLists, процесс сериализации будет работать. Проблема с TreeMap.
Является ли класс TreeMap сериализуемым? (В общем) Это из-за анонимного компаратора?
Вот основной класс с сериализацией
public class Main
{
public static void main(String args[])
{
Central cent = Central.getInstance();
FileOutputStream fos;
ObjectOutputStream oos;
cent.addUser(new Student(3,"id","pass","name","surname"));
cent.addUser(new Student(3,"id2","pass","name","surname"));
cent.addUser(new Student(3,"id1","pass","name","surname"));
try
{
fos = new FileOutputStream("save.txt");
oos = new ObjectOutputStream(fos);
oos.writeObject(cent);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
3 ответа
TreeMap содержит ссылку на компаратор, который он использует для сравнения ключей. И компаратор является экземпляром анонимного класса, который не сериализуем. Таким образом, вы получите это исключение.
Преобразуйте анонимный компаратор в высокоуровневый или именованный внутренний класс, который также реализует Serializable.
Еще один способ заставить Comparator
быть Serializable
это преобразовать его в лямбду с дополнительным приведением привязки:
TreeMap<Integer, String> sortedMap = new TreeMap<>(
(Comparator<Integer> & Serializable) (o1, o2) -> {
return o1.compareTo(o2);
}
);
Вот объяснение: лямбда-выражения Java, приведение и компараторы.
Добавьте "имплементации Serializable" в ваш Comparator, и это должно решить проблему.