2011-08-22 10 views
17

Các mã sau đây:Tại sao một lớp bên trong tuần tự không thể tuần tự hóa được?

public class TestInnerClass { 

    public static void main(String[] args) throws IOException { 
     new TestInnerClass().serializeInnerClass(); 
    } 

    private void serializeInnerClass() throws IOException { 
     File file = new File("test"); 
     InnerClass inner = new InnerClass(); 
     new ObjectOutputStream(new FileOutputStream(file)).writeObject(inner); 
    } 

    private class InnerClass implements Serializable { 

     private static final long serialVersionUID = 1L; 

    } 

} 

ném ngoại lệ sau đây:

Exception in thread "main" java.io.NotSerializableException: TestInnerClass 

Tôi đoán các lớp bên trong có một trường TestInnerClass.this cho phép nó truy cập tới TestInnerClass 's lĩnh vực và phương pháp. Khai báo lớp bên trong tĩnh solves it, nhưng điều gì sẽ xảy ra nếu InnerClass cần quyền truy cập này? Có cách nào để tuần tự hóa một lớp bên trong không tĩnh mà không có lớp kèm theo, ví dụ: bằng cách tham chiếu đến lớp bên ngoài transient?

chỉnh sửa: ví dụ: chỉ có thể truy cập vào lớp bên ngoài trước khi tuần tự hóa. OK, trình biên dịch không thể biết điều đó, nhưng tôi nghĩ đó là lý do tại sao từ khóa transient tồn tại.

+4

đã bạn cố gắng để khai báo lớp bên trong tĩnh? 'private static class InnerClass' – gnat

Trả lời

20

nếu InnerClass cần quyền truy cập này thì sao?

Sau đó, nó cần thể hiện lớp bên ngoài và phải được tuần tự hóa cùng với lớp bên trong.

Có cách nào để tuần tự hóa lớp bên trong không tĩnh mà không có lớp kèm theo, ví dụ: bằng cách làm cho tham chiếu đến lớp ngoài thoáng qua?

No. Điều gì sẽ xảy ra khi bạn deserialize lớp như vậy và sau đó cố gắng gọi một phương pháp thể hiện của lớp bên ngoài? A NullPointerException?

+1

Trong tình huống của tôi, lớp bên trong cần truy cập trước khi nó thực sự được tuần tự hóa (không phải sau khi deserialization). Sau đó nó chỉ được sử dụng như một superclass mà không biết về lớp bên ngoài. – tb189

+5

@ tb189: Bạn luôn có thể ngắt phụ thuộc không tĩnh bằng cách thêm một trường 'tạm thời TestInnerClass parentClass' vào' InnerClass' và cẩn thận khi deserializing. –

+0

Đó thực sự sẽ là một cách để đối phó với nó, và tương tự như một tham chiếu thoáng qua đến 'TestInnerClass.this'. – tb189

1

làm thế nào để làm cho TestInnerClass có thể được tuần tự hóa?

public class TestInnerClass implements Serializable { } 
+2

Điều đó là có thể, nhưng không phải lúc nào cũng mong muốn, vì nó bổ sung rất nhiều dữ liệu vào lớp được tuần tự hóa. – tb189

+0

@EJP: luôn có các giải pháp có thể thích hợp hơn (tách các phần của lớp bên trong cần truy cập và chuyển tiếp nó tới lớp tuần tự tĩnh, sử dụng trường tạm thời TestInnerClass, duy trì một đối tượng tuần tự khác trong lớp bên trong). Nó cũng ngụ ý khai báo tất cả các trường trong lớp ngoài thoáng qua, có vẻ như là một lỗ hổng thiết kế. Nó không phải vì tình hình hiện tại không hoạt động mà thay thế/hack đầu tiên nên được sử dụng ngay lập tức. – tb189

0

InnerClass không thể được đăng vì để nhanh chóng nó (theo yêu cầu trong deserialization), bạn cần một tham chiếu đến một thể hiện của lớp bên ngoài

Instances các lớp bên trong không thể tồn tại mà không có một thể hiện của lớp bên ngoài.

tức là

OuterClass o = new OuterClass(); 
OuterClass.InnerClass o_i = o.new InnerClass(); 

Nếu bạn sử dụng lớp bên trong tĩnh, nó sẽ có thể để serialise các lớp bên trong tĩnh. Các thể hiện của các lớp bên trong tĩnh có thể được tạo độc lập.

tức là

OuterClass o = new OuterClass(); 
OuterClass.InnerClass i = new OuterClass.InnerClass(); 
+0

Có lẽ tạo ra một Github Gist hoặc một ví dụ tái sản xuất đầy đủ sẽ được tốt đẹp, bạn không nghĩ? – Adonis