2009-05-20 55 views
181

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?

+41

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

+12

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 ;) –

+5

@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. –

Trả lời

78

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.

60

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:

+44

Ý 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

+0

Cảm ơn bạn vì thông tin :) – coobird

+35

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

17

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.

+1

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

+0

@grep thử đổi tên một trường và sau đó xem điều gì sẽ xảy ra. – Trejkaz

+1

@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

6

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.

+0

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

12

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ũ.

9

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 :

  1. 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.
  2. 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.
  3. 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.
  4. 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.
+0

@Downvoters Bạn có thể pliz đưa ra lý do cho downvotes. –

+0

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

+0

@mostruash go ahed ... tốt đẹp để xem cập nhật của bạn ... –

0

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.

+0

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

1

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.

3

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. :)

+0

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ó. –

+1

Đ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

Các vấn đề liên quan