Câu hỏi SerialVersionUID là gì và tại sao tôi nên sử dụng nó?


Eclipse đưa ra các cảnh báo khi một serialVersionUID bị thiếu.

Lớp Foo tuần tự không khai báo kết quả tĩnh   trường serialVersionUID loại dài

Những gì là serialVersionUID và tại sao nó quan trọng? Vui lòng hiển thị ví dụ bị thiếu serialVersionUID sẽ gây ra vấn đề.


2489
2017-11-12 23:24


gốc


Một ví dụ đơn giản mkyong.com/java-best-practices/understand-the-serialversionuid - Gopinagh.R


Các câu trả lời:


Các tài liệu cho java.io.Serializable có lẽ là một lời giải thích tốt như bạn sẽ nhận được:

Các thời gian chạy serialization liên kết   với mỗi lớp serializable một phiên bản   số, được gọi là serialVersionUID,   được sử dụng trong quá trình deserialization   để xác minh rằng người gửi và người nhận   của một đối tượng được tuần tự hóa đã được tải   các lớp cho đối tượng đó   tương thích với   tuần tự hóa. Nếu người nhận có   nạp một lớp cho đối tượng có   một serialVersionUID khác với   của lớp người gửi tương ứng,   sau đó deserialization sẽ dẫn đến một    InvalidClassException. Một serializable   lớp học có thể tự khai báo   serialVersionUID một cách rõ ràng bởi   khai báo một trường có tên   "serialVersionUID"đó phải là   tĩnh, cuối cùng và loại long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Nếu một   lớp serializable không rõ ràng   khai báo một serialVersionUID, sau đó   thời gian chạy tuần tự hóa sẽ tính toán   giá trị serialVersionUID mặc định cho   lớp đó dựa trên các khía cạnh khác nhau của   lớp học, như được mô tả trong   Thứ tự đối tượng Java (TM)   Đặc điểm kỹ thuật. Tuy nhiên nó là mạnh mẽ   đề nghị tất cả đều có thể tuần tự hóa   lớp khai báo một cách rõ ràng   giá trị serialVersionUID, vì   tính toán serialVersionUID mặc định   rất nhạy cảm với chi tiết lớp học   có thể khác nhau tùy thuộc vào trình biên dịch   triển khai và do đó có thể dẫn đến   bất ngờ InvalidClassExceptions   trong quá trình deserialization. Do đó, để   đảm bảo nhất quán   giá trị serialVersionUID trên   trình biên dịch java khác nhau   triển khai, một lớp serializable   phải tuyên bố rõ ràng   giá trị serialVersionUID. Nó cũng là   mạnh mẽ khuyên rằng rõ ràng   khai báo serialVersionUID sử dụng   sửa đổi riêng tư khi có thể, vì   những tuyên bố như vậy chỉ áp dụng cho   khai báo ngay lập tức   lớp - các trường serialVersionUID không   hữu ích như các thành viên được thừa kế.


1911
2017-11-12 23:30



Vì vậy, những gì bạn đang nói về cơ bản là nếu một người dùng không hiểu tất cả các tài liệu trên, cho biết người dùng aught không bận tâm lo lắng về serialization? Tôi tin rằng bạn đã trả lời "làm thế nào?" thay vì giải thích "tại sao?" Tôi, đối với một, không hiểu tại sao tôi aught bận tâm với SerializableVersionUID. - Ziggy
Lý do tại sao trong đoạn thứ hai: nếu bạn không chỉ định rõ ràng serialVersionUID, một giá trị được tạo ra tự động - nhưng đó là giòn vì nó thực hiện trình biên dịch phụ thuộc. - Jon Skeet
Và tại sao Eclipse nói tôi cần "serialVersionUID = 1L dài cuối cùng tĩnh riêng tư" khi tôi mở rộng lớp Ngoại lệ? - JohnMerlino
@ JohnMerlino: Tôi không mong đợi nó sẽ nói bạn nhu cầu một - nhưng có thể đề xuất một để giúp bạn serialize ngoại lệ một cách chính xác. Nếu bạn không sắp xếp chúng, bạn thực sự không cần hằng số. - Jon Skeet
@ JohnMerlino, để trả lời lý do tại sao một phần câu hỏi của bạn: Ngoại lệ thực hiện Có thể tuần tự và nhật thực cảnh báo rằng bạn đã không thiết lập một serialVersionUID, mà sẽ là một ý tưởng tốt (nếu bạn không muốn serialize lớp) để tránh những vấn đề mà bài viết của JonSkeet vạch ra. - zpon


Nếu bạn sắp xếp tuần tự chỉ vì bạn phải tuần tự hóa vì mục đích thực hiện (ai quan tâm nếu bạn serialize cho HTTPSession, ví dụ ... nếu nó được lưu trữ hay không, bạn có thể không quan tâm đến việc de-serializing một đối tượng form) , sau đó bạn có thể bỏ qua điều này.

Nếu bạn đang thực sự sử dụng serialization, nó chỉ quan trọng nếu bạn có kế hoạch lưu trữ và lấy các đối tượng sử dụng serialization trực tiếp. SerialVersionUID đại diện cho phiên bản lớp của bạn, và bạn nên tăng nó nếu phiên bản hiện tại của lớp của bạn không tương thích ngược với phiên bản trước đó của nó.

Hầu hết thời gian, bạn có thể sẽ không sử dụng serialization trực tiếp. Nếu trường hợp này xảy ra, hãy tạo uid có thể tuần tự mặc định bằng cách nhấp vào tùy chọn sửa lỗi nhanh và đừng lo lắng về điều đó.


415
2017-11-13 04:24



Tôi muốn nói rằng nếu bạn không sử dụng serialization cho lưu trữ vĩnh viễn, bạn nên sử dụng @SuppressWarnings thay vì thêm một giá trị. Nó clutters lớp ít hơn, và nó bảo tồn abiity của cơ chế serialVersionUID để bảo vệ bạn khỏi những thay đổi không tương thích. - Tom Anderson
Tôi không thấy làm thế nào thêm một dòng (@SuppressWarnings chú thích) như trái ngược với một dòng (id serializable) "clutters lớp ít hơn". Và nếu bạn không sử dụng serialization cho lưu trữ vĩnh viễn, tại sao bạn sẽ không chỉ sử dụng "1"? Bạn sẽ không quan tâm đến ID được tạo tự động trong trường hợp đó. - MetroidFan2002
@ MetroidFan2002: Tôi nghĩ rằng điểm @ TomAnderson của serialVersionUID bảo vệ bạn khỏi những thay đổi không tương thích là hợp lệ. Sử dụng @SuppressWarnings tài liệu ý định tốt hơn nếu bạn không muốn sử dụng lớp để lưu trữ vĩnh viễn. - AbdullahC
"Bạn nên tăng nó nếu phiên bản hiện tại của lớp không tương thích ngược với phiên bản trước của nó:" Trước tiên bạn nên khám phá hỗ trợ phiên bản đối tượng mở rộng của Tuần tự hóa, (a) để đảm bảo rằng lớp đó thực sự là cách không tương thích serialization, mà theo đặc điểm kỹ thuật là khá khó khăn để đạt được; (b) để thử một sơ đồ như các phương thức read / writeObject () tùy chỉnh, các phương thức readResolve / writeReplace (), các khai báo serializableFields, vv, để đảm bảo luồng đó vẫn tương thích. Thay đổi thực tế serialVersionUID là một phương sách cuối cùng, một lời khuyên về tuyệt vọng. - user207421
@EJP increment của serialVersionUID đi vào hình ảnh khi tác giả ban đầu của lớp đã giới thiệu một cách rõ ràng.Tôi sẽ nói, jvm tạo id nối tiếp, nên được tốt. đây là thứ tốt nhất câu trả lời mà tôi thấy trên serialization. - overexchange


Tôi không thể bỏ qua cơ hội này để đọc cuốn sách của Josh Bloch Java hiệu quả (Ấn bản lần 2). Chương 11 là một nguồn tài nguyên không thể thiếu trong tuần tự hóa Java.

Per Josh, UID được tạo tự động được tạo dựa trên tên lớp, giao diện được triển khai và tất cả các thành viên được bảo vệ và công khai. Thay đổi bất kỳ cách nào trong số này theo bất kỳ cách nào sẽ thay đổi serialVersionUID. Vì vậy, bạn không cần phải gây rối với họ chỉ khi bạn chắc chắn rằng không có nhiều hơn một phiên bản của lớp sẽ bao giờ được serialized (hoặc qua các quá trình hoặc lấy từ lưu trữ tại một thời gian sau đó).

Nếu bạn bỏ qua chúng ngay bây giờ, và tìm thấy sau đó bạn cần phải thay đổi lớp theo một cách nào đó nhưng duy trì tính tương thích với phiên bản cũ của lớp, bạn có thể sử dụng công cụ JDK bộ nối tiếp để tạo ra serialVersionUID trên  lớp và đặt rõ ràng rằng trên lớp mới. (Tùy thuộc vào các thay đổi của bạn, bạn có thể cần phải triển khai thực hiện tuần tự hóa tùy chỉnh bằng cách thêm writeObject và readObject phương pháp - xem Serializable javadoc hoặc chương 11 nói trên)


264
2017-11-12 23:37



Vì vậy, một trong những có thể bận tâm với SerializableVersionUID nếu một trong những lo ngại về khả năng tương thích w / phiên bản cũ của một lớp học? - Ziggy
Yup, trong trường hợp nếu phiên bản mới hơn thay đổi bất kỳ thành viên nào được bảo vệ, thì SerializableVersionUID mặc định sẽ khác và sẽ tăng một InvalidClassExceptions. - Chander Shivdasani
Tên lớp, giao diện được triển khai, tất cả các phương thức công cộng và được bảo vệ, TẤT CẢ các biến mẫu. - Achow
Điều đáng chú ý là Joshua Bloch khuyên rằng mỗi Serializable lớp nó có giá trị xác định các phiên bản nối tiếp uid. Trích dẫn từ chương 11: Bất kể bạn đã chọn dạng tuần tự nào, hãy khai báo một UID phiên bản nối tiếp rõ ràng trong mọi lớp tuần tự mà bạn viết. Điều này giúp loại bỏ UID phiên bản nối tiếp như là một nguồn tiềm năng không tương thích (Mục 74). Ngoài ra còn có một lợi ích hiệu suất nhỏ. Nếu không có UID phiên bản nối tiếp nào được cung cấp, một tính toán đắt tiền là cần thiết để tạo ra một khi chạy. - Ashutosh Jindal


Bạn có thể yêu cầu Eclipse bỏ qua các cảnh báo serialVersionUID này:

Cửa sổ> Tuỳ chọn> Java> Trình biên dịch> Lỗi / Cảnh báo> Sự cố lập trình tiềm năng

Trong trường hợp bạn không biết, có rất nhiều cảnh báo khác bạn có thể kích hoạt trong phần này (hoặc thậm chí có một số báo cáo là lỗi), nhiều cảnh báo rất hữu ích:

  • Vấn đề lập trình tiềm năng: Có thể gán boolean ngẫu nhiên
  • Vấn đề lập trình tiềm năng: Truy cập con trỏ
  • Mã không cần thiết: Biến cục bộ không bao giờ được đọc
  • Mã không cần thiết: Kiểm tra không cần thiết
  • Mã không cần thiết: Cast không cần thiết hoặc 'instanceof'

và nhiều cái khác.


124
2017-11-13 01:17



upvote nhưng chỉ vì các poster ban đầu không xuất hiện để được serializing bất cứ điều gì. Nếu người đăng nói "Tôi đang sắp xếp thứ này và ..." thì bạn sẽ nhận được phiếu bầu thay vì: P - John Gardner
Đúng - Tôi đã giả định người hỏi đơn giản là không muốn bị cảnh báo - matt b
@Gardner -> đồng ý! Nhưng người hỏi cũng muốn biết tại sao anh ta có thể không muốn được cảnh báo. - Ziggy
Người hỏi rõ ràng quan tâm đến lý do tại sao nên có một UID. Vì vậy, chỉ cần nói với anh ta để bỏ qua cảnh báo nên được downvoted. - cinqS


serialVersionUID tạo điều kiện cho việc phiên bản dữ liệu được tuần tự hóa. Giá trị của nó được lưu trữ với dữ liệu khi tuần tự hóa. Khi de-serializing, cùng một phiên bản được kiểm tra để xem dữ liệu tuần tự khớp với mã hiện tại như thế nào.

Nếu bạn muốn phiên bản dữ liệu của mình, bạn thường bắt đầu bằng serialVersionUID 0, và bump nó với mọi thay đổi cấu trúc cho lớp của bạn làm thay đổi dữ liệu tuần tự hóa (thêm hoặc loại bỏ các trường không phải là tạm thời).

Cơ chế de-serialization được tích hợp sẵn (in.defaultReadObject()) sẽ từ chối không tuần tự hóa từ các phiên bản cũ của dữ liệu. Nhưng nếu bạn muốn bạn có thể xác định readObject ()- chức năng có thể đọc lại dữ liệu cũ. Mã tùy chỉnh này sau đó có thể kiểm tra serialVersionUID để biết phiên bản nào của dữ liệu và quyết định cách loại bỏ nó. Kỹ thuật tạo phiên bản này rất hữu ích nếu bạn lưu trữ dữ liệu tuần tự mà tồn tại một số phiên bản mã của bạn.

Nhưng lưu trữ dữ liệu tuần tự cho một khoảng thời gian dài như vậy không phải là rất phổ biến. Thường sử dụng cơ chế tuần tự hóa để ghi tạm thời dữ liệu vào ví dụ một bộ nhớ cache hoặc gửi nó qua mạng tới một chương trình khác với cùng phiên bản của các phần liên quan của codebase.

Trong trường hợp này bạn không quan tâm đến việc duy trì khả năng tương thích ngược. Bạn chỉ quan tâm đến việc đảm bảo rằng các cơ sở mã đang giao tiếp thực sự có cùng phiên bản của các lớp có liên quan. Để tạo điều kiện kiểm tra như vậy, bạn phải duy trì serialVersionUIDgiống như trước và không quên cập nhật nó khi thực hiện thay đổi cho lớp học của bạn.

Nếu bạn quên cập nhật trường, bạn có thể kết thúc với hai phiên bản khác nhau của một lớp với cấu trúc khác nhau nhưng với cùng một serialVersionUID. Nếu điều này xảy ra, cơ chế mặc định (in.defaultReadObject()) sẽ không phát hiện bất kỳ sự khác biệt nào và cố gắng loại bỏ dữ liệu không tương thích. Bây giờ bạn có thể kết thúc với một lỗi thời gian chạy khó hiểu hoặc lỗi im lặng (các trường rỗng). Các loại lỗi này có thể khó tìm.

Vì vậy, để giúp hệ thống này, nền tảng Java cung cấp cho bạn một lựa chọn không thiết lập serialVersionUID bằng tay. Thay vào đó, một băm của cấu trúc lớp sẽ được tạo ra tại thời gian biên dịch và được sử dụng làm id. Cơ chế này sẽ đảm bảo rằng bạn không bao giờ có các cấu trúc lớp khác nhau với cùng một id và vì vậy bạn sẽ không nhận được các lỗi tuần tự hóa thời gian chạy khó theo dõi được đề cập ở trên.

Nhưng có một mặt sau cho chiến lược id được tạo tự động. Cụ thể là các id được tạo cho cùng một lớp có thể khác nhau giữa các trình biên dịch (như đã đề cập bởi Jon Skeet ở trên). Vì vậy, nếu bạn giao tiếp dữ liệu tuần tự hóa giữa mã được biên dịch với các trình biên dịch khác nhau, bạn nên duy trì các id theo cách thủ công.

Và nếu bạn tương thích ngược với dữ liệu của mình như trong trường hợp sử dụng đầu tiên được đề cập, bạn cũng có thể muốn tự mình duy trì id. Điều này để có được các id có thể đọc được và kiểm soát tốt hơn thời điểm và cách chúng thay đổi.


96
2017-10-03 06:05



Việc thêm hoặc loại bỏ các trường không phải là tạm thời không làm cho việc tuần tự hóa lớp không tương thích. Do đó, không có lý do gì để 'va đập nó' trên những thay đổi như vậy. - user207421
@ EJP: Huh? Thêm dữ liệu chắc chắn thay đổi dữ liệu tuần tự hóa trong thế giới của tôi. - Alexander Torstling
@AlexanderTorstling Đọc những gì tôi đã viết. Tôi đã không nói nó không 'thay đổi dữ liệu tuần tự hóa'. Tôi nói nó 'không làm cho lớp serialization-incompatible'. Nó không phải là điều tương tự. Bạn cần đọc chương Versioning của đặc tả Serialization Object. - user207421
@EJP: Tôi nhận thấy rằng việc thêm trường không tạm thời không nhất thiết có nghĩa là bạn làm cho lớp không tương thích, nhưng đó là thay đổi cấu trúc làm thay đổi dữ liệu tuần tự và bạn thường muốn chạy phiên bản khi làm như vậy trừ khi bạn xử lý khả năng tương thích ngược, mà tôi cũng đã giải thích sau trong bài đăng. Điểm của bạn chính xác là gì? - Alexander Torstling
Quan điểm của tôi vẫn chính xác những gì tôi nói. Việc thêm hoặc loại bỏ các trường không phải là tạm thời không làm cho lớp Serialization không tương thích. Do đó bạn không cần phải bump serialVersionUID mỗi khi bạn làm như vậy. - user207421


Một là gì serialVersionUID và tại sao tôi nên sử dụng nó?

SerialVersionUID là số nhận dạng duy nhất cho mỗi lớp, JVM sử dụng nó để so sánh các phiên bản của lớp, đảm bảo rằng cùng một lớp được sử dụng trong quá trình tuần tự hóa được tải trong Deserialization.

Chỉ định một cho phép kiểm soát nhiều hơn, mặc dù JVM tạo ra một điều khiển nếu bạn không chỉ định. Giá trị được tạo có thể khác nhau giữa các trình biên dịch khác nhau. Hơn nữa, đôi khi bạn chỉ muốn một số lý do để cấm deserialization của các đối tượng serialized cũ [backward incompatibility] và trong trường hợp này, bạn chỉ cần thay đổi serialVersionUID.

Các javadocs cho Serializable Nói:

tính toán serialVersionUID mặc định rất nhạy cảm với lớp   chi tiết có thể khác nhau tùy thuộc vào việc triển khai trình biên dịch và có thể   do đó dẫn đến bất ngờ InvalidClassExceptiontrong thời gian   deserialization.

Do đó, bạn phải khai báo serialVersionUID vì nó cho chúng ta nhiều quyền kiểm soát hơn.

bài viết này có một số điểm tốt về chủ đề này.


62
2017-10-17 04:28



@Vinothbabu nhưng serialVersionUID là tĩnh nên các biến tĩnh không thể được tuần tự hóa. sau đó làm thế nào đến jvm sẽ kiểm tra phiên bản, mà không biết phiên bản của đối tượng deserializing là gì - Kranthi Sama
Một điều không được đề cập trong câu trả lời này là bạn có thể gây ra những hậu quả ngoài ý muốn bằng cách bao gồm một cách mù quáng serialVersionUID mà không biết tại sao. Nhận xét của Tom Anderson về câu trả lời của MetroidFan2002 giải quyết vấn đề này: "Tôi muốn nói rằng nếu bạn không sử dụng serialization để lưu trữ vĩnh viễn, bạn nên sử dụng @SuppressWarnings thay vì thêm một giá trị. Nó cắt lớp ít hơn, và nó bảo toàn khả năng của cơ chế serialVersionUID để bảo vệ bạn khỏi những thay đổi không tương thích. " - Kirby
serialVersionUIDLà không phải 'số nhận dạng duy nhất cho mỗi lớp'. Tên lớp học đầy đủ là điều đó. Nó là một phiên bản chỉ báo. - user207421


Câu hỏi ban đầu đã yêu cầu 'tại sao nó quan trọng' và 'ví dụ' ở đây Serial Version ID Sẽ hữu ích. Vâng, tôi đã tìm thấy một.

Giả sử bạn tạo Car , khởi tạo nó và viết nó ra một luồng đối tượng. Các đối tượng xe phẳng ngồi trong hệ thống tập tin một thời gian. Trong khi đó, nếu Car lớp được sửa đổi bằng cách thêm một trường mới. Sau đó, khi bạn cố gắng đọc (tức là deserialize) thì phẳng Car đối tượng, bạn có được java.io.InvalidClassException - bởi vì tất cả các lớp serializable được tự động đưa ra một định danh duy nhất. Ngoại lệ này được ném khi định danh của lớp không bằng với định danh của đối tượng phẳng. Nếu bạn thực sự nghĩ về nó, ngoại lệ được ném vì sự bổ sung của trường mới. Bạn có thể tránh ngoại lệ này được ném bằng cách tự kiểm soát phiên bản bằng cách khai báo một serialVersionUID rõ ràng. Ngoài ra còn có một lợi ích hiệu suất nhỏ trong tuyên bố rõ ràng của bạn serialVersionUID(vì không phải tính toán). Vì vậy, cách tốt nhất là thêm serialVersionUID của riêng bạn vào các lớp Serializable của bạn ngay khi bạn tạo chúng như hình dưới đây:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

42
2018-04-07 10:43



Và một nên gán một số ngẫu nhiên dài, không phải 1L, cho mọi UID. - abbas
@abbas 'Một nên' làm điều đó tại sao? Vui lòng giải thích sự khác biệt của nó. - user207421
Như tên gọi, nó đại diện cho phiên bản của lớp đã được sử dụng để sắp xếp từng đối tượng. Nếu bạn chỉ định cùng một số mỗi lần, bạn sẽ không thể tìm thấy lớp phù hợp để hủy tuần tự. Vì vậy, bất cứ khi nào bạn thực hiện một sự thay đổi trong lớp học, nó là tốt hơn để thay đổi phiên bản quá. - abbas
@abbas, ý định này không xung đột với việc sử dụng các số tự nhiên tăng lên từ 1 và vân vân. - Vadzim
@BillK, tôi nghĩ rằng kiểm tra tuần tự hóa được ràng buộc với cặp classname và serialVersionUID. Vì vậy, các lược đồ đánh số khác nhau của các lớp và thư viện khác nhau không thể can thiệp theo bất kỳ cách nào. Hay bạn ngụ ý các thư viện tạo mã? - Vadzim


Nếu bạn nhận được cảnh báo này trên một lớp học mà bạn không bao giờ nghĩ về việc sắp xếp theo thứ tự, và bạn không tự khai báo implements Serializable, thường là vì bạn được thừa hưởng từ một lớp cha, thực hiện Serializable. Thường thì sẽ tốt hơn khi ủy quyền cho một đối tượng như vậy thay vì sử dụng thừa kế.

Vì vậy, thay vì

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

làm

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

và trong các cuộc gọi phương thức có liên quan myList.foo() thay vì this.foo() (hoặc là super.foo()). (Điều này không phù hợp trong mọi trường hợp, nhưng vẫn khá thường xuyên.)

Tôi thường thấy mọi người mở rộng JFrame hoặc như vậy, khi họ thực sự chỉ cần ủy quyền cho điều này. (Điều này cũng giúp tự động hoàn thành trong một IDE, vì JFrame có hàng trăm phương thức, mà bạn không cần khi bạn muốn gọi các tùy chỉnh của mình trên lớp của bạn.)

Một trường hợp cảnh báo (hoặc serialVersionUID) là không thể tránh khỏi là khi bạn mở rộng từ AbstractAction, thường trong một lớp ẩn danh, chỉ thêm phương thức actionPerformed. Tôi nghĩ rằng không nên có một cảnh báo trong trường hợp này (vì bạn thường không thể tuần tự hóa đáng tin cậy và deserialize các lớp ẩn danh như vậy trên các phiên bản khác nhau của lớp học của bạn), nhưng tôi không chắc chắn làm thế nào trình biên dịch có thể nhận ra điều này.


33
2018-02-03 00:32



Tôi nghĩ rằng bạn đang đúng rằng thành phần trên vô nhân tạo có ý nghĩa hơn, đặc biệt là khi bạn đang thảo luận về các lớp học như ArrayList. Tuy nhiên, nhiều khung công tác yêu cầu mọi người mở rộng từ các lớp siêu trừu tượng có thể tuần tự hóa (chẳng hạn như lớp ActionForm của Struts 1.2, hoặc ExtensionFunctionDefinition của Saxon) trong trường hợp giải pháp này là không khả thi. Tôi nghĩ rằng bạn đúng, nó sẽ được tốt đẹp nếu cảnh báo đã bị bỏ qua trong trường hợp nhất định (như nếu bạn đang mở rộng từ một lớp serializable trừu tượng) - piepera
Chắc chắn nếu bạn thêm một lớp làm thành viên, thay vì kế thừa từ nó, bạn sẽ phải viết một phương thức bao bọc cho phương thức MỌI của lớp thành viên mà bạn muốn sử dụng, điều này sẽ làm cho nó không khả thi trong một số lượng lớn các tình huống .. trừ khi java có một chức năng tương tự như của perl __AUTOLOADmà tôi không biết. - M_M
@M_M: Khi bạn sẽ ủy thác rất nhiều phương thức cho đối tượng được bao bọc của mình, tất nhiên nó sẽ không thích hợp để sử dụng ủy nhiệm. Nhưng tôi cho rằng trường hợp này là dấu hiệu của lỗi thiết kế - người dùng của lớp học của bạn (ví dụ: "MainGui") không cần phải gọi nhiều phương thức của đối tượng được bao bọc (ví dụ: JFrame). - Paŭlo Ebermann
Những gì tôi không thích về phái đoàn là cần phải giữ một tham chiếu đến các đại biểu. Và mọi tham chiếu đều có nghĩa là nhiều bộ nhớ hơn. Đúng nếu tôi sai. Nếu tôi cần một CustomArrayList của 100 đối tượng thì điều này sẽ không quan trọng lắm nhưng nếu tôi cần hàng trăm CustomizdeArrayLists của một vài đối tượng thì việc sử dụng bộ nhớ sẽ tăng đáng kể. - WVrock
Throwable là serializable, và chỉ Throwable là throwable, do đó, nó không thể xác định một ngoại lệ mà không phải là serializable. Không thể ủy quyền. - Phil


Nếu bạn sẽ không bao giờ cần serialize các đối tượng của bạn vào mảng byte và gửi / lưu trữ chúng, thì bạn không cần phải lo lắng về nó. Nếu bạn làm thế, thì bạn phải xem xét serialVersionUID của bạn vì deserializer của đối tượng sẽ khớp nó với phiên bản của đối tượng mà trình nạp lớp của nó có. Đọc thêm về nó trong Đặc tả Ngôn ngữ Java.


30
2017-11-12 23:30



Nếu bạn không sắp xếp các đối tượng, thì tại sao chúng lại có thể Serializable? - erickson
@erickson - lớp cha có thể được serializable, ArrayList, nhưng bạn muốn đối tượng của riêng bạn (nói, một danh sách mảng sửa đổi) để sử dụng nó như là một cơ sở nhưng sẽ không bao giờ serialize Bộ sưu tập mà bạn tạo ra. - MetroidFan2002
Nó không được đề cập ở đâu trong Đặc tả Ngôn ngữ Java. Nó được đề cập trong Đặc tả Phiên bản Đối tượng. - user207421
Đây là liên kết đến Java 8 Đặc tả phiên bản đối tượng. - Basil Bourque


Để hiểu tầm quan trọng của trường serialVersionUID, ta nên hiểu cách Serialization / Deserialization hoạt động như thế nào.

Khi một đối tượng lớp Serializable được tuần tự hóa Java Runtime liên kết một phiên bản nối tiếp số (được gọi là serialVersionUID) với đối tượng được tuần tự hóa này. Vào thời điểm khi bạn deserialize đối tượng serialized Java Runtime này khớp với serialVersionUID của đối tượng serialized với serialVersionUID của lớp đó. Nếu cả hai đều bằng nhau thì chỉ có nó tiến hành với quá trình tiếp tục deserialization khác ném InvalidClassException.

Vì vậy, chúng tôi kết luận rằng để làm cho quá trình Serialization / Deserialization thành công serialVersionUID của đối tượng serialized phải tương đương với serialVersionUID của lớp. Trong trường hợp nếu lập trình viên xác định giá trị serialVersionUID một cách rõ ràng trong chương trình thì giá trị tương tự sẽ được kết hợp với đối tượng tuần tự và lớp, không phân biệt nền tảng tuần tự hóa và deserialzation (cho serialization cũ có thể được thực hiện trên nền tảng như windows bằng cách sử dụng mặt trời hoặc MS JVM và Deserialization có thể là trên nền tảng Linux khác nhau sử dụng Zing JVM).

Nhưng trong trường hợp nếu serialVersionUID không được chỉ định bởi lập trình viên thì trong khi thực hiện Serialization \ DeSerialization của bất kỳ đối tượng nào, thời gian chạy Java sử dụng thuật toán riêng của nó để tính toán nó. Thuật toán tính toán serialVersionUID này thay đổi từ JRE này sang JRE khác. Cũng có thể môi trường nơi đối tượng được tuần tự hóa đang sử dụng một JRE (ví dụ: SUN JVM) và môi trường mà deserialzation xảy ra đang sử dụng Linux Jvm (zing). Trong trường hợp này, serialVersionUID được kết hợp với đối tượng được tuần tự hóa sẽ khác với serialVersionUID của lớp được tính toán tại môi trường deserialzation. Lần lượt deserialization sẽ không thành công. Vì vậy, để tránh các tình huống / vấn đề lập trình viên phải luôn luôn chỉ định serialVersionUID của lớp Serializable.


19
2018-06-02 06:20



Thuật toán không thay đổi, nhưng nó không được chỉ định một chút. - user207421