2013-07-23 32 views
12

Tôi có một giao diện cho các hạng mục lọc:NotSerializableException trên lớp nặc danh

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); 
} 

và một lớp có chứa một thành viên của loại KeyValFilter.

public class KeyValFilterCollector extends KeyValCollectorSkeleton { 
/** 
* 
*/ 
private static final long serialVersionUID = -3364382369044221888L; 
KeyValFilter filter; 
public KeyValFilterCollector(KeyValFilter filter){ 
    this.filter=filter; 
} 

Khi tôi cố gắng để bắt đầu KeyValFilterCollector với một lớp vô danh thực hiện 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:"); 
     } 
    }); 

tôi nhận được một ngoại lệ: Exception in thread "main" java.io.NotSerializableException Làm thế nào để làm cho lớp vô danh tôi đã viết Serializable?

Trả lời

22

Joshua Bloch viết trong cuốn sách của ông Effective Java, 2nd Edition, khoản 74:

lớp Inner không nên thực hiện Serializable. Họ sử dụng các trường hợp tổng hợp do biên dịch tạo ra để biên dịch các tham chiếu đến trường hợp kèm theo và để lưu trữ các giá trị của biến cục bộ từ phạm vi kèm theo. Làm thế nào các trường tương ứng với định nghĩa lớp là không xác định, như là tên của các lớp ẩn danh và cục bộ. Do đó, dạng tuần tự mặc định của một lớp bên trong là illdefined. Tuy nhiên, lớp thành viên tĩnh có thể thực hiện Serializable.

+2

Tôi đã xác định bộ lọc thành viên là tĩnh và đã giải quyết được sự cố. – Shaharg

0

Bạn có thể khai báo lớp có thể tuần tự vô danh, nhưng lớp này chỉ sau đó thực sự có thể tuần tự hóa, nếu tất cả các trường của nó có thể tuần tự hóa được.

Xem ví dụ:

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!"); 
} 

Nếu bạn nhận xét dòng

private Object ns = new Object(){}; 

Mã này đã kết thúc với thành công, nếu không NotSerializableException được ném.

+0

Điều này mô tả tình hình chung của tất cả các trường không phải là thoáng qua cần phải được tuần tự hóa trên một lớp thực hiện 'Serializable', không cụ thể là một lớp ẩn danh. –

8

Thông thường, vấn đề được thấy khi tuần tự hóa lớp ẩn danh là lớp kèm theo không được tuần tự hóa (và tác giả không nhận ra rằng tuần tự hóa một lớp ẩn danh liên quan đến việc tuần tự hóa lớp kèm theo của nó).

Lớp ẩn danh là lớp bên trong không tĩnh. Điều đó có nghĩa là nó có một trường ẩn tham chiếu đến một thể hiện của lớp kèm theo. Khi bạn tạo nó với new KeyValFilter(){ ... }, mà không đủ điều kiện rõ ràng (ví dụ: something.new KeyValFilter(){ ... }), thì this được sử dụng ngầm làm trường hợp của lớp kèm theo (như thể bạn đã làm this.new KeyValFilter(){ ... }). Vì vậy, khi bạn tuần tự hóa lớp ẩn danh, yêu cầu tuần tự hóa tất cả các trường của nó, một trong số đó là thể hiện của lớp kèm theo, mà sau đó phải được tuần tự hóa.

Nếu bạn không cần sử dụng bất kỳ trường hoặc phương thức nào của lớp kèm theo, bạn nên sử dụng lớp bên trong tĩnh thay thế. (Tuy nhiên, nó không thể ẩn danh hoặc được định nghĩa bên trong phương thức.)

+0

"và tác giả không nhận ra rằng việc tuần tự hóa một lớp ẩn danh liên quan đến việc tuần tự hóa lớp bao quanh của nó". Đây chính là vấn đề của tôi. Cảm ơn gợi ý này. – asmaier

Các vấn đề liên quan