2009-11-02 35 views
13

Tôi có một lớp học dành cho việc sử dụng bất biến, do đó tôi muốn gắn nhãn tất cả các trường final.Serialising và các đối tượng không thay đổi

Tuy nhiên, lớp được đăng và được tuần tự hóa để gửi qua mạng. Đối với điều này để làm việc một constructor rỗng là bắt buộc. Điều này ngăn cản tôi tạo các trường cuối cùng.

Tôi chắc chắn đây là vấn đề khá phổ biến nhưng tôi không thể tìm thấy giải pháp. Tôi nên tiến hành như thế nào?

Trả lời

7

Trong trường hợp tuần tự hóa điển hình, không bắt buộc phải có lớp khởi tạo trống hoặc trường cuối cùng không thể tuần tự hóa được.

Bây giờ, nếu bạn phải làm serialization của riêng bạn, hoặc bạn cần phải phân lớp một lớp mà không thực hiện Serializable, đó là một câu chuyện khác nhau.

Vì vậy, bạn cần cung cấp thêm một số chi tiết về cách bạn đang gặp sự cố.

+1

Cảm ơn, tôi đã sử dụng phương pháp đặc trưng của serialization nhưng đã luôn luôn cung cấp một constructor rỗng như đó là làm thế nào tôi nghĩ rằng nó làm việc. – Pool

6

Một hàm tạo no-arg là không bắt buộc. Lớp non-serialisable có nguồn gốc nhất không cần một hàm tạo no-arg có sẵn cho lớp serialisable có nguồn gốc thấp nhất.

Nếu bạn cần thay đổi trường bên trong một readObject, sau đó sử dụng proxy nối tiếp thông qua readResolvewriteReplace.

5

Sự cố này là open bug on the Java language. (Lưu ý rằng điều này chỉ áp dụng nếu bạn phải thực hiện tuần tự theo cách thủ công, chẳng hạn như với readObject)

+0

Từ đánh giá: "vấn đề áp dụng cho các trường hợp cuối cùng khác với các trường có thể tuần tự hóa của lớp" vì vậy trong trường hợp chuẩn, nó hoạt động tốt. Nick dường như đang làm điều gì đó khác biệt. – Yishai

+0

Ah vâng, tôi nên thêm tuyên bố từ chối trách nhiệm rằng điều này chỉ áp dụng nếu bạn phải móc vào readObject hoặc một cái gì đó tương tự. –

3

Để lặp lại những gì đã được nói, nhà thầu no-arg không phải là yêu cầu nếu bạn đang thực hiện giao diện java.io.Serializable . Hãy xem mã nguồn java.lang.Integer ví dụ, một lớp có thể tuần tự/không thay đổi đơn giản có hai hàm tạo: một hàm nhận một int và một hàm nhận một String. Mã nguồn: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.

Cũng tùy thuộc vào độ phức tạp của lớp và những gì bạn đang làm, bạn có thể xem xét việc triển khai tuần tự qua giao diện java.io.Externalizable (mặc dù một số coi nó lỗi thời và yêu cầu một hàm tạo không có arg). Dưới đây là tổng quan về SO: What is the difference between Serializable and Externalizable in Java? và đây là hướng dẫn Java chính thức: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.

3

Đối với hồ sơ, vì tôi đã có một vấn đề tương tự:
Tôi đã có một thông báo "java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar, không có nhà xây dựng có giá trị"

Tôi nghĩ đó là vì nó thiếu một hàm tạo mặc định. Nhưng các câu trả lời trên xác nhận nó không phải là bắt buộc (nhưng ứng dụng của chúng tôi. Sử dụng một serializer cũ mà thực sự đòi hỏi một constructor mặc định, vì vậy trường hợp có thể phát sinh).

Sau đó, tôi tìm thấy một trang nêu:

Nếu một lớp học được thiết kế cho các thừa kế không phải là serializable, nó có thể không thể viết một phân lớp serializable. Cụ thể, nó sẽ là không thể nếu siêu lớp không cung cấp một hàm tạo tham số có thể truy cập.

Do đó, tôi nhận được thông báo.Nó xuất hiện rằng vấn đề cốt lõi là cổ điển: Tôi tuyên bố một lớp như serializable, nhưng siêu lớp không phải là! Tôi đã di chuyển giao diện Serializable lên trong hệ thống phân cấp và tất cả đều tốt.

Nhưng thông báo có một chút gây hiểu lầm ... :-)

0

Một hàm tạo no-arg là không bắt buộc. Hãy đọc mã nguồn:

// java.io.ObjectStreamClass 
private static Constructor<?> getSerializableConstructor(Class<?> cl) { 
    Class<?> initCl = cl; 
    while (Serializable.class.isAssignableFrom(initCl)) { 
     if ((initCl = initCl.getSuperclass()) == null) { 
      return null; 
     } 
    } 
    ... 
} 

Vì vậy, trên thực tế các nhà xây dựng không-arg là cần thiết trong tương lai không Serializable lớp gần nhất trong hệ thống phân cấp loại.

Điều đó có nghĩa là lớp sau Domain có thể được tuần tự hóa.

class Domain implements Serializable { 
    private final int a; 

    public Domain(int a) { 
     this.a = a; 
    } 
} 

Nhưng lớp Son không thể:

class Father{ 
    private final int a; 

    public Father(int a) { 
    this.a = a; 
    } 
} 

class Son extends Father implements Serializable { 
    public Son(int a) { 
    super(a); 
    } 
} 
Các vấn đề liên quan