Сериализация локального класса, возвращенного из вызываемого объекта
Это мозгократчер.
Я знаю, что этот фактический код ужасен на стольких уровнях. Мой вопрос не Как это сделать (я знаю о статических блоках инициализации), но Почему это не работает, в интересах моего понимания сериализации Java.
Почему это работает
import java.io.*;
import java.util.*;
class Main {
static Comparator<String> COMPARE_STRING_LENGTH;
static {
class CompareStringReverse implements Comparator<String>, Serializable {
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
COMPARE_STRING_LENGTH = new CompareStringReverse();
}
public static void main(String[] args) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test.ser"));
out.writeObject(new TreeSet<String>(COMPARE_STRING_LENGTH));
out.close();
}
}
Пока это
import java.io.*;
import java.util.*;
import java.util.concurrent.Callable;
class Main {
static Comparator<String> COMPARE_STRING_LENGTH = new Callable<Comparator<String>>() {
public Comparator<String> call() {
class CompareStringReverse implements Comparator<String>, Serializable {
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
return new CompareStringReverse();
}
}.call();
public static void main(String[] args) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test.ser"));
out.writeObject(new TreeSet<String>(COMPARE_STRING_LENGTH));
out.close();
}
}
Выходы
Exception in thread "main" java.io.NotSerializableException: Main$1
1 ответ:
Ну, "почему"немного тонко. Хотя ваш именованный класс (
CompareStringReverse
) реализуетSerializable
, он вложен ванонимный класс, который этого не делает. поэтому он является внутренним классом и имеет неявную ссылку на экземпляр заключающего анонимного класса. Например, если вы выполните:javap -c Main$1$1CompareStringReverse
Вы увидите поле:
Это то, что не может быть сериализовано. Вы все еще можете легко исправить это, хотя:final Main$1 this$0;
interface SerializableCallable<T> extends Serializable, Callable<T> {} ... static Comparator<String> COMPARE_STRING_LENGTH = new SerializableCallable<Comparator<String>>() { ... };
Единственное существенное различие-это что анонимный класс теперь реализует
Serializable
, а такжеCallable<T>
. Я не думаю, что существует какой-либо способ указать несколько интерфейсов для реализации анонимного класса (т. е. вам нужно создать дополнительный интерфейс, чтобы объединить их), но я могу ошибаться.Итак, теперь именованный внутренний класс реализует
Serializable
, а также тип его единственного поля, так что все работает.