NotSerializableException в анонимном классе
У меня есть интерфейс для фильтрации элементов:
public interface KeyValFilter extends Serializable{
public static final long serialVersionUID = 7069537470113689475L;
public boolean acceptKey(String iKey, Iterable<String> iValues);
public boolean acceptValue(String iKey, String value);
}
и класс, содержащий элемент типа KeyValFilter.
public class KeyValFilterCollector extends KeyValCollectorSkeleton {
/**
*
*/
private static final long serialVersionUID = -3364382369044221888L;
KeyValFilter filter;
public KeyValFilterCollector(KeyValFilter filter){
this.filter=filter;
}
Когда я пытаюсь инициировать KeyValFilterCollector с анонимным классом, реализующим KeyValFilter:
new KeyValFilterCollector(new KeyValFilter(){
private static final long serialVersionUID = 7069537470113689475L;
public boolean acceptKey(String iKey, Iterable<String> iValues){
for (String value : iValues) {
if (value.startsWith("1:"))
return true;
}
return false;
}
public boolean acceptValue(String iKey, String value){
return value.startsWith("0:");
}
});
Я получаю исключение: Исключение в потоке "main" java.io.NotSerializableException
Как сделать анонимный класс я написал Serializable?
Ответы
Ответ 1
Джошуа Блох пишет в своей книге Эффективная Java, 2-е издание, пункт 74:
Внутренние классы не должны реализовывать Serializable
. Они используют синтезированные поля, созданные компилятором, для хранения ссылок на окружающие экземпляры и для хранения значений локальных переменных из охватывающих областей. Как эти поля соответствуют определению класса не определены, как и имена анонимных и локальных классов. Поэтому стандартная сериализованная форма внутреннего класса не определена. Однако статический класс-член может реализовать Serializable
.
Ответ 2
Обычно проблема, возникающая при сериализации анонимного класса, заключается в том, что охватывающий класс не является сериализуемым (и автор не понял, что сериализация анонимного класса включает сериализацию его охватывающего класса).
Анонимный класс - нестатический внутренний класс. Это означает, что у него есть скрытое поле, которое ссылается на экземпляр окружающего класса. Когда вы создаете его с помощью new KeyValFilter(){ ... }
, без явного определения его (например, something.new KeyValFilter(){ ... }
), то this
неявно используется как экземпляр класса-оболочки (как если бы вы делали this.new KeyValFilter(){ ... }
). Поэтому, когда вы сериализуете анонимный класс, который требует сериализации всех его полей, один из которых является экземпляром охватывающего класса, который затем должен быть сериализуемым.
Если вам не нужно использовать какие-либо поля или методы окружающего класса, вместо этого вы должны использовать статический внутренний класс. (Однако он не может быть анонимным или определен внутри метода.)
Ответ 3
Вы можете объявить анонимный класс serializable, но класс только тогда действительно сериализуем, если все его поля сериализуемы.
См. пример:
public static void main(String[] args) throws Exception {
Object myObj = new Serializable() {
private static final long serialVersionUID = 1L;
private String str = "something";
private Object ns = new Object(){};
};
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(myObj);
oos.close();
System.out.println("Success!");
}
Если вы прокомментируете строку
private Object ns = new Object(){};
Код завершен с успехом, в противном случае NotSerializableException
.