Khi lớp thực hiện Serializable trong Eclipse, tôi có hai tùy chọn: thêm mặc định serialVersionUID(1L)
hoặc tạo serialVersionUID(3567653491060394677L)
. Tôi nghĩ rằng đầu tiên là mát hơn, nhưng nhiều lần tôi thấy mọi người sử dụng tùy chọn thứ hai. Có lý do nào để tạo ra long serialVersionUID
không?Tại sao tạo serialVersionUID dài thay vì 1L đơn giản?
Trả lời
Theo như tôi có thể biết, điều đó chỉ phù hợp với các bản phát hành trước đó. Điều này sẽ chỉ hữu ích nếu bạn bỏ qua sử dụng một serialVersionUID trước, và sau đó thực hiện một thay đổi mà bạn biết nên là compatible nhưng gây ra serialization để phá vỡ.
Xem Java Serialization Spec để biết thêm chi tiết.
Mục đích của phiên bản tuần tự UID là theo dõi các phiên bản khác nhau của một lớp để thực hiện tuần tự hóa các đối tượng hợp lệ.
Ý tưởng là để tạo ra một ID đó là duy nhất cho một phiên bản nhất định của một lớp, sau đó được thay đổi khi có những chi tiết mới được thêm vào lớp, chẳng hạn như một lĩnh vực mới, trong đó sẽ ảnh hưởng đến cấu trúc của serialized vật.
Luôn luôn sử dụng cùng một ID, chẳng hạn như 1L
có nghĩa là trong tương lai, nếu định nghĩa lớp được thay đổi gây ra những thay đổi trong cấu trúc của đối tượng đăng, sẽ có một cơ hội tốt mà vấn đề khi cố gắng deserialize một đối tượng .
Nếu ID được bỏ qua, Java sẽ thực sự tính toán ID cho bạn dựa trên các lĩnh vực của đối tượng, nhưng tôi tin rằng nó là một quá trình tốn kém, vì vậy cung cấp một cách thủ công sẽ cải thiện hiệu suất.
đây của một vài liên kết đến các bài viết thảo luận serialization và phiên bản của các lớp:
- JDC Tech Tips: February 29, 2000(liên kết bị phá vỡ như tháng Hai 2013)
- Discover the secrets of the Java Serialization API
Ý tưởng đằng sau việc sử dụng 1L là để bạn tăng nó mỗi khi bạn thay đổi thuộc tính hoặc phương thức của lớp. – Powerlord
Cảm ơn bạn vì thông tin :) – coobird
Không có tác động hiệu suất thời gian chạy cho phép serialversionUID được tạo tự động - nó được tạo ra tại thời gian biên dịch bởi javac ... nếu bạn dịch ngược bytecode của lớp, bạn sẽ thực sự thấy biến tĩnh trong bytecode. – Jared
Nguyên nhân chủ yếu cho phiên bản được tạo ra sẽ làm cho nó tương thích với một phiên bản hiện có của lớp đã có các bản sao đã tồn tại.
OK nhưng như vậy sẽ là Nếu tôi luôn luôn 1L. Mọi thứ sẽ tương thích ngay cả khi tôi sẽ thực hiện bất kỳ thay đổi nào. – grep
@grep thử đổi tên một trường và sau đó xem điều gì sẽ xảy ra. – Trejkaz
@grep điểm là nếu bạn có một lớp mà bỏ qua serialVersionUID trước đây, nó sẽ tự động nhận được tạo ra. Vì vậy, bây giờ, bạn muốn bắt đầu thiết lập nó một cách rõ ràng, thiết lập nó thành 1L sẽ làm cho nó không tương thích với lớp hiện có, trong khi việc sử dụng giá trị đã tạo sẽ giữ nó tương thích. – marc82ch
Nếu bạn không chỉ định serialVersionUID thì Java sẽ thực hiện thao tác này khi đang di chuyển. SerialVersionUID được tạo ra là số đó. Nếu bạn thay đổi một cái gì đó trong lớp của bạn mà không thực sự làm cho lớp của bạn không tương thích với verisons tuần tự trước đó nhưng thay đổi băm, sau đó bạn cần phải sử dụng serialVersionUID rất lớn được tạo ra (hoặc số "dự kiến" từ thông báo lỗi) . Ngược lại, nếu bạn đang theo dõi mọi thứ cho mình, 0, 1, 2 ... là tốt hơn.
Bạn có nghĩa là ==> 1. Nếu bạn muốn thay đổi khác nhau của các lớp học để tương thích sử dụng một tạo ra. 2. Nếu bạn muốn các phiên bản khác nhau của các lớp không tương thích, hãy sử dụng phiên bản mặc định và cẩn trọng khi tăng dần.Tôi có hiểu nó đúng không? – JavaDeveloper
Giá trị mặc định "dài" của serialVersionUID
là giá trị mặc định như được xác định bởi Java Serialization Specification, được tính từ hành vi tuần tự hóa mặc định. Vì vậy, nếu bạn thêm số phiên bản mặc định, lớp của bạn sẽ (xóa) nhanh hơn miễn là không có gì thay đổi về cấu trúc, nhưng bạn sẽ phải cẩn thận nếu bạn thay đổi lớp (thêm/xóa trường) bạn cũng cập nhật số sê-ri.
Nếu bạn không phải tương thích với luồng bit hiện tại, bạn có thể chỉ cần đặt 1L
tại đó và tăng phiên bản khi cần khi có điều gì đó thay đổi. Đó là, khi phiên bản serialization mặc định của lớp thay đổi sẽ khác với phiên bản mặc định của lớp cũ.
Bạn hoàn toàn nên tạo serialVersionUID mỗi khi bạn xác định một lớp thực hiện java.io.Serializable
. Nếu không, bạn sẽ tự động tạo cho mình nhưng điều này không tốt. Số tự động tạo ra serialVersionUID được dựa trên chữ ký của lớp học của bạn, vì vậy nếu bạn thay đổi lớp học của mình trong tương lai để thêm phương thức (ví dụ), deserializing các phiên bản "cũ" của lớp sẽ không thành công. Đây là những gì có thể xảy ra :
- Tạo phiên bản đầu tiên của lớp học của bạn, mà không xác định serialVersionUID.
- Sắp xếp từng phiên bản của lớp học thành cửa hàng liên tục; a serialVersionUID được tạo tự động cho bạn.
- Sửa đổi lớp học của bạn để thêm phương thức mới và triển khai lại ứng dụng của bạn.
- Cố gắng deserialize trường hợp đã được đăng trong bước 2, nhưng bây giờ nó không thành công (khi nó nên thành công), bởi vì nó có khác nhau được tạo tự động serialVersionUID.
@Downvoters Bạn có thể pliz đưa ra lý do cho downvotes. –
Như một vấn đề của thực tế, deserializing phiên bản cũ của lớp nên thực sự thất bại vì họ không giống nhau nữa. Bạn đề nghị tạo serialVersionUID bằng chính mình để ngăn chặn (de) thất bại tuần tự khi chữ ký lớp thay đổi. Mặc dù đề xuất của bạn là phù hợp, nhưng giải thích của bạn về mục đích của nó chỉ đơn giản là sai và gây hiểu nhầm. Nó sẽ là khôn ngoan để sửa đổi câu trả lời của bạn. – mostruash
@mostruash go ahed ... tốt đẹp để xem cập nhật của bạn ... –
Vì trong nhiều trường hợp, id mặc định không phải là duy nhất. vì vậy chúng tôi tạo id để tạo khái niệm độc đáo.
Bạn có thể chỉnh sửa câu trả lời của bạn để xác thịt thêm? Điều này có vẻ giống như một bình luận ở đây. Cảm ơn. – Gray
Vâng, serialVersionUID là ngoại lệ đối với quy tắc “trường tĩnh không được đăng theo thứ tự”. ObjectOutputStream viết mỗi khi giá trị của serialVersionUID đến luồng đầu ra. ObjectInputStream đọc nó trở lại và nếu giá trị đọc từ dòng không đồng ý với giá trị serialVersionUID trong phiên bản hiện tại của lớp, sau đó nó ném InvalidClassException. Hơn nữa, nếu không có serialVersionUID được khai báo chính thức trong lớp được tuần tự hóa, trình biên dịch sẽ tự động thêm nó với một giá trị được tạo ra dựa trên các trường được khai báo trong lớp.
Khi bạn sử dụng serialVersionUID (1L) thay vì tạo serialVersionUID (3567653491060394677L), bạn đang nói điều gì đó.
Bạn đang nói rằng bạn là 100% tự tin rằng không có hệ thống đó bao giờ sẽ chạm vào lớp này có một phiên bản tương thích serialized của lớp này với một số phiên bản của 1.
Nếu bạn có thể nghĩ ra bất kỳ lý do gì để lịch sử phiên bản được tuần tự hóa không được biết, có thể khó nói với sự tự tin. Trong cuộc đời của nó, một lớp học thành công sẽ được duy trì bởi nhiều người, sống trong nhiều dự án, và cư trú trong nhiều hệ thống.
Bạn có thể khổ sở về điều đó. Hoặc bạn có thể chơi xổ số hy vọng sẽ thua. Nếu bạn tạo ra phiên bản bạn có một cơ hội nhỏ của những điều đi sai. Nếu bạn giả sử "Này tôi cá là không ai sử dụng 1", tỷ lệ cược của bạn lớn hơn rất nhỏ. Đó là chính xác bởi vì tất cả chúng ta nghĩ rằng 0 và 1 là mát mẻ mà bạn có tỷ lệ cược cao hơn đánh chúng.
-
Khi bạn tạo serialVersionUID (3567653491060394677L) thay vì sử dụng serialVersionUID (1L), bạn đang nói cái gì đó.
Bạn đang nói mọi người có thể đã tạo thủ công hoặc tạo ra các số phiên bản khác trong lịch sử của lớp này và bạn không quan tâm vì Longs đang freaking số lớn. Dù là cách nào trừ khi bạn hoàn toàn biết lịch sử của các số phiên bản được sử dụng khi sắp xếp từng lớp trong toàn bộ vũ trụ nơi nó có hoặc sẽ tồn tại, bạn sẽ có cơ hội.Nếu bạn có thời gian để đảm bảo 100% 1 là AOK, hãy thực hiện nó. Nếu đó là để làm việc nhiều, đi trước và mù quáng tạo ra số lượng. Bạn có nhiều khả năng thắng xổ số hơn là điều đó sai. Nếu có, hãy cho tôi biết và tôi sẽ mua cho bạn một ly bia.
Với tất cả bài nói chuyện về chơi xổ số này, tôi có thể đã cho bạn ấn tượng rằng serialVersionUID được tạo ngẫu nhiên. Trong thực tế miễn là phạm vi của các con số được phân bố đều trên mọi giá trị có thể có của một Long mà sẽ là tốt. Tuy nhiên, nó thực sự được thực hiện theo cách này:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
Sự khác biệt duy nhất mà bạn nhận được với đó là bạn không cần một nguồn ngẫu nhiên. Bạn đang sử dụng các thay đổi trong chính lớp đó để thay đổi kết quả. Nhưng theo nguyên tắc pigeonhole vẫn còn một cơ hội nó có thể đi sai và có một vụ va chạm. Nó chỉ là vô cùng khó xảy ra. Vì vậy, may mắn nhận được một ly bia ra khỏi tôi.
Tuy nhiên, ngay cả khi lớp học sẽ chỉ sống trong một hệ thống và một cơ sở mã, hãy nghĩ rằng việc tăng số bằng tay cho bạn không có cơ hội va chạm chỉ có nghĩa là bạn không hiểu con người. :)
Nếu một "hệ thống" chạm vào lớp, tức là thay đổi lớp theo cách mà việc tuần tự hóa trở nên không tương thích thì câu hỏi là nếu hệ thống đó cũng sẽ thay đổi serialVersionUID. Tôi không nghĩ rằng tỷ lệ cược nhỏ hơn mà nó sẽ nhớ thay đổi nó khi nó dài. Tôi nghĩ rằng ngược lại là đúng, nếu số dễ nhớ hơn thay đổi cao hơn mà tôi nhận thấy rằng tôi vô tình đã không thay đổi nó. –
Điều này là sai! Khi bạn tạo serialVersionUID và khai báo giá trị đó trong mã nguồn của bạn, chứ không phải 1L hoặc không có gì bạn đang thực sự nói: Tôi muốn một va chạm có thể không bị phát hiện trong tương lai với các hiệu ứng không xác định và tôi không muốn java hoặc bất kỳ người nào ngăn chặn điều này . Java là hoang tưởng, nhưng vâng lời. Con người thường không gây rối với số lượng lớn. Bằng cách này, khi lớp học thay đổi, java vẫn có thể de-serialize phiên bản không tương thích cũ của nó. MwoaHaHa ...;) – Superole
- 1. static final serialVersionUID dài = 1L
- 2. Tại sao sử dụng ROLAP thay vì MySQL đơn giản?
- 3. Tại sao std :: cout thay vì chỉ đơn giản là cout?
- 4. Tại sao tạo HTML đơn giản thông qua PHP heredoc?
- 5. Tại sao FloatBuffer thay vì phao []?
- 6. Tại sao nhập chương trình đơn giản <Foundation/Foundation.h> thay vì tệp tiêu đề riêng lẻ?
- 7. tab đơn giản sử dụng fragmentactivity thay vì tabactivity
- 8. Tại sao testFixture thay vì TestClass?
- 9. Tại sao CHỌN 0, ... thay vì CHỌN
- 10. Tại sao sử dụng singleton thay vì phương pháp tĩnh?
- 11. Tại sao hàm tạo bản sao này được gọi thay vì hàm tạo di chuyển?
- 12. Tại sao hàm tạo bản sao được gọi thay vì hàm tạo chuyển đổi?
- 13. Tại sao darcs thay vì git?
- 14. Tại sao NDEBUG thay vì RELEASE?
- 15. Tại sao nhập javax.swing. * Thay vì java.swing. *
- 16. Tại sao chặn thay vì lặp?
- 17. Tại sao CompositionTarget.Rendering lấy EventArgs thay vì RenderingEventArgs?
- 18. Thay thế libtool đơn giản?
- 19. Tại sao dịch vụ đơn giản này không bắt đầu?
- 20. Tại sao tạo chủ đề mới bằng startAsync thay vì làm việc trong chuỗi servlet?
- 21. Tại sao thuật toán haskell đơn giản này lại chậm?
- 22. Tại sao trình biên dịch Java lại tạo trường tổng hợp serialVersionUID?
- 23. Giới thiệu về serialVersionUID được tạo trong Eclipse
- 24. Tại sao JSFiddle đơn giản này không hoạt động?
- 25. Tại sao frame-> pts tăng 20, thay vì 1?
- 26. Tại sao sử dụng phương thức khởi tạo thay vì hàm tạo?
- 27. Tại sao numpy.r_ sử dụng dấu ngoặc vuông thay vì dấu ngoặc đơn?
- 28. Tại sao khối khởi tạo tĩnh không chạy trong trường hợp đơn giản này?
- 29. Http đơn giản thay thế cho Wireshark
- 30. Tại sao Stream.Position lại dài
Sao chép chính xác như vậy? Tôi không hỏi tại sao tạo ra nó ở tất cả, nhưng tại sao tạo dài serialVersionUID. – IAdapter
Khi Jon Skeet sử dụng serialVersionUID, anh ta sử dụng 0L: http://stackoverflow.com/questions/605828/does-it-matter-what-i-choose-for-serialversionuid-when-extending-serializable-cla/605832#605832 ;) –
@HannoFietz: Câu chính xác là: "Để đơn giản tôi đề nghị ** bắt đầu ** với 0 và ** tăng nó lên 1 ** mỗi lần bạn cần." Vì vậy, có vẻ như anh ấy chỉ sử dụng '0L' ban đầu. –