Kiedy klasa implementuje Serializable w Eclipse, mam dwie opcje: dodaj domyślną serialVersionUID(1L)
lub wygenerowaną serialVersionUID(3567653491060394677L)
. Myślę, że ten pierwszy jest fajniejszy, ale wiele razy widziałem ludzi używających drugiej opcji. Czy istnieje jakiś powód do wygenerowania long serialVersionUID
?
210
0L
tylko na początku.Odpowiedzi:
O ile mi wiadomo, byłoby to zgodne tylko z poprzednimi wersjami. Przydałoby się to tylko wtedy, gdy wcześniej zaniedbałeś użycie serialVersionUID, a następnie dokonałeś zmiany, o której wiesz, że powinna być kompatybilna, ale powoduje zerwanie serializacji.
Więcej informacji można znaleźć w specyfikacji Java Serialization Spec .
źródło
Identyfikator UID wersji serializacji służy do śledzenia różnych wersji klasy w celu przeprowadzenia prawidłowej serializacji obiektów.
Chodzi o to, aby wygenerować identyfikator, który jest unikalny dla określonej wersji klasy, która jest następnie zmieniana, gdy do klasy dodawane są nowe szczegóły, takie jak nowe pole, które wpłynęłoby na strukturę szeregowanego obiektu.
Zawsze przy użyciu tego samego identyfikatora, na przykład
1L
oznacza, że w przyszłości, jeśli zmieni się definicja klasy, co spowoduje zmiany w strukturze serializowanego obiektu, istnieje duża szansa, że pojawią się problemy podczas próby deserializacji obiektu.Jeśli identyfikator zostanie pominięty, Java faktycznie obliczy dla Ciebie identyfikator na podstawie pól obiektu, ale uważam, że jest to kosztowny proces, więc podanie go ręcznie poprawi wydajność.
Oto kilka linków do artykułów omawiających serializację i wersjonowanie klas:
źródło
Note - It is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail.
. Powyższy komentarz pochodzi z specyfikacji Java Object Serialization Specification 6.0Głównym powodem wygenerowania jednego byłoby dostosowanie go do istniejącej wersji klasy, która już zachowała kopie.
źródło
„Długa” wartość domyślna
serialVersionUID
jest wartością domyślną zdefiniowaną w specyfikacji Java Serialization Specification , obliczoną na podstawie domyślnego zachowania serializacji.Więc jeśli dodasz domyślny numer wersji, twoja klasa będzie (od-) serializować szybciej, dopóki nic się nie zmieni strukturalnie, ale musisz uważać, że jeśli zmienisz klasę (dodaj / usuń pola), zaktualizujesz również numer seryjny.
Jeśli nie musisz być zgodny z istniejącymi strumieniami bitów, możesz po prostu
1L
tam umieścić i zwiększyć wersję w razie potrzeby, gdy coś się zmieni. Oznacza to, że gdy domyślna wersja serializacji zmienionej klasy będzie inna niż domyślna wersja starej klasy.źródło
Absolutnie powinieneś utworzyć serialVersionUID za każdym razem, gdy definiujesz klasę, która implementuje
java.io.Serializable
. Jeśli tego nie zrobisz, jeden zostanie dla Ciebie automatycznie utworzony, ale to źle. Automatycznie generowany serialVersionUID opiera się na sygnaturach metod twojej klasy, więc jeśli zmienisz swoją klasę w przyszłości, aby dodać metodę (na przykład), deserializacja „starych” wersji klasy zakończy się niepowodzeniem. Oto, co może się zdarzyć:źródło
Jeśli nie określisz identyfikatora serialVersionUID, wówczas Java tworzy go w locie. Wygenerowany serialVersionUID to ten numer. Jeśli zmienisz coś w swojej klasie, co tak naprawdę nie sprawia, że twoja klasa jest niezgodna z poprzednimi serializowanymi wersjami, ale zmienia skrót, musisz użyć wygenerowanego bardzo dużej liczby serialVersionUID (lub „oczekiwanej” liczby z komunikatu o błędzie) . W przeciwnym razie, jeśli sam wszystko śledzisz, 0, 1, 2 ... jest lepszy.
źródło
Kiedy używasz serialVersionUID (1L) zamiast generowania serialVersionUID (3567653491060394677L), coś mówisz.
Mówisz, że masz 100% pewności, że żaden system, który nigdy nie dotknie tej klasy, miałby niezgodną wersję tej klasy z serializacją o numerze wersji 1.
Jeśli wymyślisz jakieś usprawiedliwienie dla nieznanej historii wersji serializowanej, może to być trudne do powiedzenia z pewnością. Za jego życia wiele osób będzie utrzymywać udaną klasę, żyć w wielu projektach i przebywać w wielu systemach.
Możesz nad tym męczyć. Lub możesz zagrać na loterii, mając nadzieję na przegraną. Jeśli wygenerujesz wersję, masz małe szanse, że coś pójdzie nie tak. Jeśli założysz „Hej, założę się, że nikt jeszcze nie użył 1”, Twoje szanse są większe niż małe. Właśnie dlatego, że wszyscy uważamy, że 0 i 1 są fajne, masz większe szanse na ich trafienie.
-
Kiedy generujesz serialVersionUID (3567653491060394677L) zamiast używać serialVersionUID (1L), coś mówisz.
Mówisz, że ludzie mogli ręcznie tworzyć lub generować inne numery wersji w historii tej klasy i nie obchodzi cię to, ponieważ Longs cholernie duże liczby.
Tak czy inaczej, chyba że doskonale znasz historię numerów wersji używanych do serializacji klasy w całym wszechświecie, w którym istnieje lub będzie istnieć, ryzykujesz. Jeśli masz czas, aby upewnić się w 100%, że 1 to AOK, idź. Jeśli to za dużo pracy, śmiało wygeneruj liczbę. Bardziej prawdopodobne jest, że wygrasz na loterii niż popełnisz błąd. Jeśli tak, daj mi znać, a kupię ci piwo.
Po tych wszystkich rozmowach na temat gry w loterię mogłem sprawiać wrażenie, że serialVersionUID jest generowany losowo. W rzeczywistości, o ile zakres liczb jest równomiernie rozłożony na każdą możliwą wartość Długości, co byłoby w porządku. Jednak tak naprawdę dzieje się tak:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
Jedyną różnicą, jaką możesz z tym zrobić, jest to, że nie potrzebujesz źródła losowego. Używasz zmian w samej klasie, aby zmienić wynik. Ale zgodnie z zasadą szufladki nadal istnieje szansa, że może się nie udać i dojść do kolizji. To jest po prostu niezwykle mało prawdopodobne. Życzę powodzenia w wydostaniu ze mnie piwa.
Jednak nawet jeśli klasa będzie żyła tylko w jednym systemie i jednej bazie kodu, myślenie, że ręczne zwiększenie liczby daje zerową szansę na kolizję, oznacza po prostu, że nie rozumiesz ludzi. :)
źródło
Cóż, serialVersionUID jest wyjątkiem od reguły, że „pola statyczne nie są serializowane”. ObjectOutputStream zapisuje za każdym razem wartość serialVersionUID do strumienia wyjściowego. ObjectInputStream odczytuje go z powrotem i jeśli wartość odczytana ze strumienia nie zgadza się z wartością serialVersionUID w bieżącej wersji klasy, wówczas zgłasza wyjątek InvalidClassException. Ponadto, jeśli nie ma oficjalnie zadeklarowanego serialVersionUID w klasie do serializacji, kompilator automatycznie dodaje go z wartością wygenerowaną na podstawie pól zadeklarowanych w klasie.
źródło
Ponieważ w wielu przypadkach domyślny identyfikator nie jest unikalny. więc tworzymy id do stworzenia unikalnej koncepcji.
źródło
Aby dodać do @David Schmitts odpowiedź, jako ogólną zasadę zawsze używałbym domyślnej 1L poza konwencją. Musiałem tylko cofnąć się i zmienić niektóre z nich kilka razy, ale wiedziałem o tym, kiedy dokonałem zmiany i aktualizowałem domyślny numer o jeden za każdym razem.
W mojej obecnej firmie wymagają one automatycznie wygenerowanego numeru, więc używam go do konwencji, ale wolę domyślny. Uważam, że jeśli nie jest to konwencja, w której pracujesz, użyj domyślnej, chyba że uważasz, że z jakiegoś powodu będziesz ciągle zmieniać strukturę swoich serializowanych klas.
źródło
Identyfikator UID wersji serializacji służy do śledzenia różnych wersji klasy w celu przeprowadzenia prawidłowej serializacji obiektów.
Chodzi o to, aby wygenerować identyfikator, który jest unikalny dla określonej wersji klasy, która jest następnie zmieniana, gdy do klasy dodawane są nowe szczegóły, takie jak nowe pole, które wpłynęłoby na strukturę szeregowanego obiektu.
Proste wyjaśnienie:
Czy serializujesz dane?
Serializacja polega zasadniczo na zapisywaniu danych klasy do pliku / strumienia / etc. Dezserializacja polega na odczytywaniu tych danych z powrotem do klasy.
Czy zamierzasz wejść do produkcji?
Jeśli tylko testujesz coś z nieistotnymi / fałszywymi danymi, nie przejmuj się tym (chyba że bezpośrednio testujesz serializację).
Czy to jest pierwsza wersja?
Jeśli tak, ustaw serialVersionUID = 1L.
Czy to druga, trzecia itd. Wersja produktu?
Teraz musisz się martwić o serialVersionUID i powinieneś zajrzeć do niego dogłębnie.
Zasadniczo, jeśli nie zaktualizujesz wersji poprawnie podczas aktualizacji klasy, musisz zapisać / odczytać, podczas próby odczytania starych danych pojawi się błąd.
źródło