2010-05-25 9 views
40

Tôi có một lớp xác định một loại giá trị bất biến mà bây giờ tôi cần phải tuần tự hóa. Tính bất biến xuất phát từ các trường cuối cùng được đặt trong hàm tạo. Tôi đã thử serializing, và nó hoạt động (đáng ngạc nhiên?) - Nhưng tôi không có ý tưởng như thế nào.Làm thế nào để java serialization deserialize các lĩnh vực cuối cùng khi không có constructor mặc định được chỉ định?

Dưới đây là một ví dụ của lớp

public class MyValueType implements Serializable 
{ 
    private final int value; 

    private transient int derivedValue; 

    public MyValueType(int value) 
    { 
     this.value = value; 
     this.derivedValue = derivedValue(value); 
    } 

    // getters etc... 
} 

Cho rằng lớp không có không có constructor arg, làm thế nào nó có thể được khởi tạo và các lĩnh vực thiết lập cuối cùng?

(An sang một bên -. Tôi nhận thấy lớp này đặc biệt vì IDEA đã không tạo ra một "không serialVersionUID" thanh tra cảnh báo cho các lớp học này, nhưng cảnh báo được tạo ra thành công cho các lớp khác mà tôi đã chỉ cần thực hiện serializable)

+0

Câu hỏi bổ sung: cách thể hiện của một lớp * ẩn danh được đăng theo thứ tự? – ewernli

+0

Một dự đoán - nó có thể tuần tự hóa chỉ khi một trong các siêu kiểu của nó được tuần tự hóa và lớp kèm theo có thể được tuần tự hóa? Điều đó có vẻ hợp lý, nhưng có ai đó đoán được những gì trong JLS. – mdma

+0

Nó không phải 'bất cứ ai đoán được những gì trong JLS'. Nó ở đó để được ai đó đọc. – EJP

Trả lời

34

Deserialization được thực hiện bởi JVM trên một mức độ thấp hơn các cấu trúc ngôn ngữ cơ bản. Cụ thể, nó không gọi bất kỳ hàm tạo nào.

+2

Trên thực tế, nó gọi là constructor parameterless. Chỉ có các lớp với một hàm tạo như vậy được tuần tự hóa. – Oak

+11

@Oak. Không đúng. Bạn có thể tuần tự hóa một lớp mà không có một hàm tạo mặc định. –

+2

@ Alexander: xấu của tôi. Tôi đã nhầm lẫn nó với thực tế là các siêu lớp không tuần tự hóa với các kiểu serializable phải có một hàm tạo như vậy. – Oak

14

Cho rằng lớp không có hàm tạo arg, làm sao nó có thể được khởi tạo và trường cuối cùng được đặt?

Một số phép thuật đen khó chịu xảy ra. Có một backdoor trong JVM cho phép một đối tượng được tạo ra mà không cần gọi bất kỳ constructor nào. Các trường của đối tượng mới được khởi tạo lần đầu tiên với các giá trị mặc định của chúng (false, 0, null, etc), và sau đó mã deserialization đối tượng điền vào các trường có các giá trị từ luồng đối tượng.

(Bây giờ Java là nguồn mở, bạn có thể đọc các mã mà thực hiện điều này ... và khóc!)

+4

Trong thực tế, bạn thậm chí không cần ma thuật đen khó chịu, phản chiếu (a.k.a. ma thuật xám khó chịu;) có thể được sử dụng để thiết lập các trường cuối cùng. Nó hoạt động miễn là các giá trị được thiết lập trước khi các trường được đọc lần đầu tiên. – gustafc

+4

@gustafc - nhưng cần có ma thuật đen để tạo đối tượng mà không cần thực hiện bất kỳ công cụ xây dựng nào. –

11

Cả Michael và Stephen đã cho bạn một câu trả lời tuyệt vời, tôi chỉ muốn cảnh báo bạn về các lĩnh vực transient .

Nếu giá trị mặc định (null để tham chiếu, 0 đối với nguyên thủy) không được chấp nhận cho chúng sau khi deserialization thì bạn phải cung cấp phiên bản readObject và khởi tạo ở đó.

private void readObject (
      final ObjectInputStream s 
     ) throws 
      ClassNotFoundException, 
      IOException 
    { 
     s.defaultReadObject(); 

     // derivedValue is still 0 
     this.derivedValue = derivedValue(value); 
    } 
+0

Nhận xét tuyệt vời, cảm ơn ví dụ. –