Co to jest serialVersionUID i dlaczego powinienem go używać?

2998

Zaćmienie wydaje ostrzeżenia, gdy serialVersionUIDbrakuje jakiegoś .

Klasyfikowalna klasa Foo nie deklaruje statycznego końcowego pola serialVersionUID typu long

Co to jest serialVersionUIDi dlaczego jest ważne? Pokaż przykład, w którym brak serialVersionUIDspowoduje problem.

Ashokgelal
źródło
1
Znajdź dobrą praktykę dotyczącą serialversionUID; dzone.com/articles/what-is-serialversionuid
ceyun

Odpowiedzi:

2289

Dokumenty dla java.io.Serializablesą prawdopodobnie tak dobrym wyjaśnieniem, jak można uzyskać:

Środowisko wykonawcze serializacji przypisuje do każdej klasy możliwej do serializacji numer wersji, zwany a serialVersionUID, który jest używany podczas deserializacji w celu sprawdzenia, czy nadawca i odbiorca obiektu serializowanego załadowali klasy dla tego obiektu, które są kompatybilne w odniesieniu do serializacji. Jeśli odbiorca załadował klasę dla obiektu, który ma inną serialVersionUIDklasę niż klasa odpowiedniego nadawcy, deserializacja spowoduje InvalidClassException. Klasa możliwa do serializacji może serialVersionUIDjawnie zadeklarować swoją własną , deklarując nazwane pole, serialVersionUIDktóre musi być statyczne, końcowe i typu long:

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

Jeśli klasa serialVersionUIDmożliwa do serializacji nie deklaruje jawnie a , środowisko wykonawcze serializacji obliczy serialVersionUIDwartość domyślną dla tej klasy na podstawie różnych aspektów tej klasy, jak opisano w specyfikacji serializacji obiektu Java (TM). Jednak zdecydowanie zaleca się, aby wszystkie klasy szeregowalne jawnie deklarowały serialVersionUIDwartości, ponieważ domyślne serialVersionUIDobliczenia są bardzo wrażliwe na szczegóły klas, które mogą się różnić w zależności od implementacji kompilatora, a zatem mogą powodować nieoczekiwane skutki InvalidClassExceptionsdeserializacji. Dlatego, aby zagwarantować spójną serialVersionUIDwartość w różnych implementacjach kompilatora Java, klasa możliwa do serializacji musi zadeklarować serialVersionUIDwartość jawną . Zdecydowanie zaleca się to również w sposób wyraźnyserialVersionUIDdeklaracje używają prywatnego modyfikatora tam, gdzie to możliwe, ponieważ takie deklaracje dotyczą tylko natychmiast deklarujących serialVersionUIDpól klasy, które nie są przydatne jako elementy dziedziczone.

Jon Skeet
źródło
325
Tak więc zasadniczo mówisz, że jeśli użytkownik nie zrozumiał wszystkich powyższych materiałów, powiedział, że nie powinien martwić się o serializację? Wierzę, że odpowiedziałeś „jak?” zamiast wyjaśniać „dlaczego?”. Ja, na przykład, nie rozumiem, dlaczego nie przeszkadza mi SerializableVersionUID.
Ziggy
365
Dlaczego w drugim akapicie: jeśli nie określisz jawnie serialVersionUID, wartość jest generowana automatycznie - ale jest krucha, ponieważ zależy od implementacji kompilatora.
Jon Skeet
14
I dlaczego Eclipse mówi, że potrzebuję „prywatnego statycznego końcowego długiego serialVersionUID = 1L;” kiedy rozszerzę klasę wyjątków?
JohnMerlino
21
@JohnMerlino: Cóż, nie spodziewałbym się, że powie, że potrzebujesz, ale może to sugerować , aby pomóc ci poprawnie serializować wyjątki. Jeśli nie zamierzasz ich serializować, naprawdę nie potrzebujesz stałej.
Jon Skeet
16
@JohnMerlino, aby odpowiedzieć na pytanie, dlaczego część twojego pytania: wyjątek implementuje Serializable, a eclipse ostrzega, że ​​nie ustawiłeś serialVersionUID, co byłoby dobrym pomysłem (jeśli nie chcesz serializować klasy), aby uniknąć problemów, które opublikował JonSkeet wytyczne.
zpon
475

Jeśli serializujesz tylko dlatego, że musisz serializować ze względu na implementację (kogo to obchodzi, jeśli serializujesz HTTPSession, na przykład ... jeśli jest przechowywany czy nie, prawdopodobnie nie obchodzi de-serializingCię obiekt formularza), możesz zignoruj ​​to.

Jeśli faktycznie używasz serializacji, ma to znaczenie tylko wtedy, gdy planujesz przechowywanie i wyszukiwanie obiektów przy użyciu serializacji bezpośrednio. serialVersionUIDReprezentuje wersję klasy i należy zwiększyć, jeśli bieżąca wersja klasy nie jest wstecznie kompatybilny z jego poprzednią wersją.

Przez większość czasu prawdopodobnie nie użyjesz serializacji bezpośrednio. W takim przypadku wygeneruj wartość domyślną SerialVersionUID, klikając opcję szybkiej poprawki i nie martw się o to.

MetroidFan2002
źródło
78
Powiedziałbym, że jeśli nie używasz serializacji do trwałego przechowywania, powinieneś użyć @SuppressWarnings zamiast dodawać wartość. Mniej zaśmieca klasę i zachowuje abijiczność mechanizmu serialVersionUID, aby chronić cię przed niezgodnymi zmianami.
Tom Anderson
25
Nie rozumiem, jak dodanie jednej linii (adnotacja @SuppressWarnings) w przeciwieństwie do innej linii (id serializable) „mniej zaśmieca klasę”. A jeśli nie używasz serializacji do trwałego przechowywania, dlaczego po prostu nie użyjesz „1”? W takim przypadku i tak nie będzie Cię obchodził automatyczny identyfikator.
MetroidFan2002
71
@ MetroidFan2002: Myślę, że ochrona @ TomAndersona serialVersionUIDprzed niezgodnymi zmianami jest słuszna . Korzystanie z @SuppressWarningsdokumentów jest lepsze, jeśli nie chcesz używać klasy do trwałego przechowywania.
AbdullahC,
11
„Powinieneś ją zwiększyć, jeśli bieżąca wersja twojej klasy nie jest wstecznie kompatybilna z poprzednią wersją:” Najpierw powinieneś zapoznać się z obszerną obsługą wersjonowania obiektowego w Serializacji, (a) aby upewnić się, że klasa naprawdę jest teraz niezgodna z serializacją, które według specyfikacji jest dość trudne do osiągnięcia; (b) wypróbować schemat, taki jak niestandardowe metody read / writeObject (), metody readResolve / writeReplace (), deklaracje serializableFields itp., aby upewnić się, że strumień pozostaje kompatybilny. Zmiana rzeczywistości serialVersionUIDjest ostatecznością, radą rozpaczy.
user207421,
4
Przyrost @EJP parametru serialVersionUID pojawia się, gdy początkowy autor klasy wyraźnie się przedstawił. Powiedziałbym, że wygenerowany identyfikator jvm powinien być w porządku. to najlepsza odpowiedź, jaką widziałem podczas serializacji.
nadmierna wymiana
307

Nie mogę przegapić okazji, by podłączyć książkę Josha Blocha „ Effective Java” (wydanie drugie). Rozdział 11 jest niezbędnym źródłem serializacji Javy.

Według Josha automatycznie generowany identyfikator UID jest generowany na podstawie nazwy klasy, zaimplementowanych interfejsów oraz wszystkich członków publicznych i chronionych. Zmiana któregokolwiek z nich w jakikolwiek sposób spowoduje zmianę serialVersionUID. Więc nie musisz z nimi zadzierać tylko wtedy, gdy masz pewność, że nie zostanie nigdy serializowanych więcej niż jedna wersja klasy (albo między procesami, albo odzyskana z pamięci w późniejszym czasie).

Jeśli zignorujesz je teraz, a później znaleźć, że trzeba zmienić klasę w jakiś sposób, ale zachować zgodność w / starej wersji klasy, można użyć narzędzia JDK serialver do wygenerowania serialVersionUIDna starej klasy i wyraźnie określone, że w nowej klasie. (W zależności od zmian może być konieczne zaimplementowanie niestandardowej serializacji przez dodanie writeObjecti readObjectmetody - patrz Serializablejavadoc lub wspomniany rozdział 11).

Scott Bale
źródło
33
Czy ktoś mógłby niepokoić się SerializableVersionUID, gdyby martwił się kompatybilnością ze starymi wersjami klasy?
Ziggy
10
Tak, w przypadku, gdy nowsza wersja zmieni dowolnego członka publicznego na chroniony, domyślny identyfikator SerializableVersionUID będzie inny i spowoduje zgłoszenie wyjątków InvalidClassExceptions.
Chander Shivdasani
3
nazwa klasy, zaimplementowane interfejsy, wszystkie metody publiczne i chronione, WSZYSTKIE zmienne instancji.
Achow
31
Warto zauważyć, że Joshua Bloch radzi, aby dla każdej klasy nadającej się do serializacji wskazać identyfikator wersji seryjnej. Cytat z rozdziału 11: Niezależnie od tego, jaką formę serializacyjną wybierzesz, zadeklaruj jawny UID wersji seryjnej w każdej pisanej klasie, którą można serializować. Eliminuje to UID wersji seryjnej jako potencjalne źródło niezgodności (pozycja 74). Istnieje również niewielka korzyść z wydajności. Jeśli nie podano identyfikatora UID w wersji szeregowej, do wygenerowania jednego w czasie wykonywania wymagane jest kosztowne obliczenie.
Ashutosh Jindal
136

Możesz powiedzieć Eclipse, aby zignorowało te ostrzeżenia serialVersionUID:

Okno> Preferencje> Java> Kompilator> Błędy / ostrzeżenia> Potencjalne problemy z programowaniem

Jeśli nie wiesz, istnieje wiele innych ostrzeżeń, które możesz włączyć w tej sekcji (a nawet niektóre zgłaszać jako błędy), wiele z nich jest bardzo przydatnych:

  • Potencjalne problemy z programowaniem: Możliwe przypadkowe przypisanie wartości logicznej
  • Potencjalne problemy z programowaniem: Brak dostępu do wskaźnika
  • Niepotrzebny kod: zmienna lokalna nigdy nie jest odczytywana
  • Niepotrzebny kod: Redundantna kontrola zerowa
  • Niepotrzebny kod: niepotrzebne przesyłanie lub „instanceof”

i wiele więcej.

matowy b
źródło
21
pozytywnie, ale tylko dlatego, że oryginalny plakat nie wydaje się niczego serializować. Gdyby na plakacie było napisane: „Serializuję to i ...”, wtedy głos byłby niższy: P
John Gardner,
3
To prawda, że ​​zakładałem, że pytający po prostu nie chciał zostać ostrzeżony
mat.
14
@Gardner -> zgodził się! Ale pytający chce również wiedzieć, dlaczego nie chce być ostrzeżony.
Ziggy
8
Pytający oczywiście dba o to, dlaczego powinien istnieć identyfikator UID. Więc po prostu powiedzenie mu, aby zignorował ostrzeżenie, powinno zostać wzięte pod uwagę.
cinqS
111

serialVersionUIDułatwia wersjonowanie zserializowanych danych. Jego wartość jest przechowywana z danymi podczas serializacji. Podczas usuwania serializacji sprawdzana jest ta sama wersja, aby zobaczyć, jak dane serializowane są zgodne z bieżącym kodem.

Jeśli chcesz zaktualizować swoje dane, zwykle zaczynasz serialVersionUIDod zera i podbijasz je przy każdej zmianie strukturalnej w swojej klasie, która zmienia zserializowane dane (dodawanie lub usuwanie nieprzechodzących pól).

Wbudowany mechanizm deserializacji ( in.defaultReadObject()) odmówi deserializacji ze starych wersji danych. Ale jeśli chcesz, możesz zdefiniować własną funkcję readObject (), która może odczytywać stare dane. Ten niestandardowy kod może następnie sprawdzić serialVersionUID, aby dowiedzieć się, w której wersji znajdują się dane, i zdecydować, w jaki sposób należy dokonać serializacji. Ta technika wersjonowania jest przydatna, jeśli przechowujesz serializowane dane, które przetrwają kilka wersji twojego kodu.

Ale przechowywanie danych zserializowanych przez tak długi okres nie jest zbyt powszechne. O wiele bardziej powszechne jest stosowanie mechanizmu serializacji do tymczasowego zapisywania danych na przykład w pamięci podręcznej lub wysyłania ich przez sieć do innego programu z tą samą wersją odpowiednich części bazy kodu.

W takim przypadku nie jesteś zainteresowany zachowaniem kompatybilności wstecznej. Zajmujesz się tylko upewnieniem się, że komunikujące się bazy kodu rzeczywiście mają te same wersje odpowiednich klas. Aby ułatwić taką kontrolę, musisz zachować ją serialVersionUIDtak jak poprzednio i nie zapomnij zaktualizować jej podczas wprowadzania zmian w swoich klasach.

Jeśli zapomnisz zaktualizować pole, możesz skończyć z dwiema różnymi wersjami klasy o innej strukturze, ale o tej samej serialVersionUID. Jeśli tak się stanie, domyślny mechanizm ( in.defaultReadObject()) nie wykryje żadnej różnicy i spróbuje usunąć serializację niekompatybilnych danych. Teraz możesz skończyć z tajemniczym błędem środowiska wykonawczego lub cichą awarią (pola zerowe). Tego rodzaju błędy mogą być trudne do znalezienia.

Aby pomóc w tym przypadku, platforma Java oferuje wybór nie ustawiania serialVersionUIDręcznie. Zamiast tego w czasie kompilacji zostanie wygenerowany skrót struktury klasy i użyty jako identyfikator. Ten mechanizm zagwarantuje, że nigdy nie będziesz mieć różnych struktur klas o tym samym identyfikatorze, a więc nie dostaniesz wspomnianych wyżej trudnych do prześledzenia błędów serializacji.

Ale istnieje strategia automatycznego generowania identyfikatorów. Mianowicie, że wygenerowane identyfikatory dla tej samej klasy mogą się różnić między kompilatorami (jak wspomniano powyżej Jon Skeet). Jeśli więc komunikujesz dane serializowane między kodem skompilowanym za pomocą różnych kompilatorów, zalecane jest ręczne utrzymanie identyfikatorów.

A jeśli jesteś wstecznie zgodny ze swoimi danymi, tak jak w pierwszym wspomnianym przypadku użycia, prawdopodobnie również chcesz sam zachować identyfikator. Ma to na celu uzyskanie czytelnych identyfikatorów i większą kontrolę nad tym, kiedy i jak się zmieniają.

Alexander Torstling
źródło
4
Dodanie lub usunięcie nieprzemijających pól nie powoduje niezgodności serializacji klas. Dlatego nie ma powodu, aby „podbijać” takie zmiany.
user207421
4
@EJP: Hę? Dodanie danych zdecydowanie zmienia dane serializacji w moim świecie.
Alexander Torstling
3
@AlexanderTorstling Przeczytaj, co napisałem. Nie powiedziałem, że to nie „zmienia danych serializacji”. Powiedziałem, że „nie powoduje niezgodności serializacji klas”. To nie to samo. Musisz przeczytać rozdział Wersjonowanie specyfikacji serializacji obiektu.
user207421
3
@EJP: Zdaję sobie sprawę, że dodanie pola nieprzemijającego niekoniecznie oznacza, że ​​sprawiasz, że klasa nie jest kompatybilna z serializacją, ale jest to zmiana strukturalna, która zmienia zserializowane dane i zwykle chcesz przy tym podbić wersję, chyba że radzić sobie z kompatybilnością wsteczną, co również wyjaśniłem w dalszej części postu. Jaki jest dokładnie twój cel?
Alexander Torstling
4
Chodzi mi o to, co dokładnie powiedziałem. Dodanie lub usunięcie nieprzemijających pól nie powoduje, że klasa Serializacja jest niezgodna. Dlatego nie musisz podbijać serialVersionUID za każdym razem, gdy to robisz.
user207421
72

Co to jest serialVersionUID i dlaczego powinienem go używać?

SerialVersionUIDjest unikalnym identyfikatorem dla każdej klasy, JVMużywa go do porównywania wersji klasy, upewniając się, że ta sama klasa została użyta podczas serializacji, jest ładowana podczas deserializacji.

Określenie jednego daje większą kontrolę, chociaż JVM generuje taki, jeśli nie zostanie określony. Wygenerowana wartość może się różnić w zależności od kompilatora. Co więcej, czasami chcesz po prostu z jakiegoś powodu zabronić deserializacji starych serializowanych obiektów [ backward incompatibility], w tym przypadku po prostu musisz zmienić serialVersionUID.

W Javadocs doSerializable powiedzenia :

domyślne obliczenie serialVersionUID jest bardzo wrażliwe na szczegóły klasy, które mogą się różnić w zależności od implementacji kompilatora, a zatem mogą powodować nieoczekiwane InvalidClassExceptions podczas deserializacji.

Dlatego musisz zadeklarować serialVersionUID, ponieważ daje nam to większą kontrolę .

Ten artykuł zawiera kilka dobrych punktów na ten temat.

Thalaivar
źródło
3
@Vothothbabu, ale serialVersionUID jest statyczny, więc zmiennych statycznych nie można serializować. jak to możliwe, że jvm sprawdzi wersję, nie wiedząc, jaka jest wersja obiektu deserializującego
Kranthi Sama
3
Jedyną rzeczą nie wymienioną w tej odpowiedzi jest to, że możesz spowodować niezamierzone konsekwencje, ślepo włączając serialVersionUIDnie wiedząc dlaczego. Komentarz Toma Andersona do odpowiedzi MetroidFan2002 rozwiązuje ten problem: „Powiedziałbym, że jeśli nie używasz serializacji do trwałego przechowywania, powinieneś użyć @SuppressWarnings zamiast dodawać wartość. Mniej zakłóca klasę i zachowuje zdolność mechanizm serialVersionUID, aby chronić Cię przed niezgodnymi zmianami. ”
Kirby,
7
serialVersionUIDto nie za „unikalny identyfikator dla każdej klasy”. Jest to w pełni kwalifikowana nazwa klasy. Jest to wskaźnik wersji .
user207421,
58

Pierwotne pytanie brzmiało: „dlaczego to ważne” i „przykład”, gdzie Serial Version IDbyłoby to przydatne. Cóż, znalazłem jeden.

Załóżmy, że tworzysz Carklasę, tworzysz ją i zapisujesz w strumieniu obiektów. Spłaszczony obiekt samochodowy przez pewien czas znajduje się w systemie plików. Tymczasem jeśli Carklasa zostanie zmodyfikowana przez dodanie nowego pola. Później, gdy spróbujesz odczytać (tj. Deserializować) spłaszczony Carobiekt, otrzymasz java.io.InvalidClassException- ponieważ wszystkie klasy możliwe do serializacji otrzymują automatycznie unikalny identyfikator. Ten wyjątek jest zgłaszany, gdy identyfikator klasy nie jest równy identyfikatorowi spłaszczonego obiektu. Jeśli naprawdę się nad tym zastanowisz, wyjątek zostanie zgłoszony z powodu dodania nowego pola. Możesz uniknąć zgłaszania tego wyjątku, samodzielnie kontrolując wersję poprzez zadeklarowanie jawnego serialVersionUID. Istnieje również niewielka korzyść z wydajności w jawnym zadeklarowaniu twojegoserialVersionUID(ponieważ nie trzeba tego obliczać). Dlatego najlepszą praktyką jest dodawanie własnego serialVersionUID do twoich Serializowalnych klas, jak tylko je utworzysz, jak pokazano poniżej:

public class Car {
    static final long serialVersionUID = 1L; //assign a long value
}
Rupesz
źródło
I do każdego UID należy przypisać losową długą liczbę, a nie 1L.
abbas
4
@abbas „Trzeba” to zrobić dlaczego? Proszę wyjaśnić, jaką to robi różnicę.
user207421,
Jak sama nazwa wskazuje, reprezentuje wersję klasy, która została użyta do serializacji obiektu. Jeśli za każdym razem przypiszesz mu ten sam numer, nie będziesz w stanie znaleźć odpowiedniej klasy, która by go odserializowała. Dlatego za każdym razem, gdy wprowadzasz zmiany w klasie, lepiej też zmienić wersję.
abbas
2
@abbas, ta intencja nie koliduje z użyciem zwiększania liczb naturalnych od 1i tak dalej.
Vadzim
2
@ Bill, myślałem, że kontrola serializacji jest powiązana z parą nazwa klasy i serialVersionUID. Tak więc różne schematy numeracji różnych klas i bibliotek nie mogą w żaden sposób kolidować. Czy sugerowałeś biblioteki do generowania kodu?
Vadzim
44

Najpierw muszę wyjaśnić, czym jest serializacja.

Serializacja pozwala na konwersję obiektu na strumień, w celu wysłania tego obiektu przez sieć LUB Zapisz do pliku LUB zapisz w DB w celu użycia litery.

Istnieją pewne zasady serializacji .

  • Obiekt można serializować tylko wtedy, gdy jego klasa lub jego nadklasa implementują interfejs Serializable

  • Obiekt jest szeregowalny (sam implementuje interfejs Serializable), nawet jeśli jego nadklasa nie jest. Jednak pierwsza nadklasa w hierarchii klasy szeregowalnej, która nie implementuje interfejsu szeregowalnego, MUSI mieć konstruktor bez argumentu. Jeśli zostanie to naruszone, readObject () wygeneruje wyjątek java.io.InvalidClassException w środowisku wykonawczym

  • Wszystkie typy pierwotne są serializowane.

  • Pola przejściowe (z modyfikatorem przejściowym) NIE są serializowane (tzn. Nie są zapisywane ani przywracane). Klasa, która implementuje Serializable, musi oznaczyć przejściowe pola klas, które nie obsługują serializacji (np. Strumień plików).

  • Pola statyczne (z modyfikatorem statycznym) nie są serializowane.

Gdy Objectjest serializowany, Java Runtime kojarzy numer wersji seryjnej aka, czyli serialVersionID.

Gdzie potrzebujemy serialVersionID: Podczas deserializacji, aby sprawdzić, czy nadawca i odbiorca są kompatybilni w odniesieniu do serializacji. Jeśli odbiornik załaduje klasę w inny sposób,serialVersionIDdeserializacja zakończy sięInvalidClassCastException.
Klasamożliwa doserializacji możeserialVersionUIDjawniezadeklarować swoją własną, deklarując nazwane pole,serialVersionUIDktóre musi być statyczne, końcowe i długiego typu.

Spróbujmy tego na przykładzie.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Utwórz obiekt serializacji

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializuj obiekt

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

UWAGA: Zmień teraz serialVersionUID klasy Employee i zapisz:

private static final long serialVersionUID = 4L;

I uruchom klasę Reader. Nie uruchamiać klasy Writer, a otrzymasz wyjątek.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
JegsVala
źródło
Popraw mnie, jeśli się mylę - klasa lokalna to ta, którą aktualnie używasz / używasz w ścieżce klasy, a strumień jest używany przez inną stronę (np. Serwer, który zwraca ci odpowiedź i serializuje odpowiedź). Możesz spotkać się z tą sytuacją, gdy komunikujesz się z serwerem, który zaktualizował biblioteki innych firm, ale ty (klient) tego nie zrobiłeś.
Victor
37

Jeśli nigdy nie będziesz musiał szeregować obiektów w celu bajtowania tablicy i wysyłania / przechowywania ich, nie musisz się tym martwić. Jeśli to zrobisz, musisz wziąć pod uwagę swój serialVersionUID, ponieważ deserializator obiektu dopasuje go do wersji obiektu, którą ma moduł ładujący klasy. Przeczytaj więcej na ten temat w specyfikacji języka Java.

eishay
źródło
10
Jeśli nie zamierzasz serializować obiektów, dlaczego można je serializować?
erickson,
7
@erickson - klasa nadrzędna może być serializowalna, powiedzmy ArrayList, ale chcesz, aby własny obiekt (powiedzmy zmodyfikowana lista tablic) używał jej jako podstawy, ale nigdy nie zamierza serializować kolekcji, którą tworzysz.
MetroidFan2002
5
Nigdzie nie wspomniano w specyfikacji języka Java. Jest wspomniany w specyfikacji wersjonowania obiektów.
user207421
4
Oto link do specyfikacji wersjonowania obiektów Java 8 .
Basil Bourque
34

Jeśli zobaczysz to ostrzeżenie w klasie, nigdy nie zastanawiasz się nad serializacją, a sam nie zadeklarowałeś implements Serializabletego, często dzieje się tak , ponieważ odziedziczyłeś po nadklasie, która implementuje Serializable. Często wtedy lepiej byłoby przekazać taki obiekt zamiast korzystać z dziedziczenia.

Więc zamiast

public class MyExample extends ArrayList<String> {

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

zrobić

public class MyExample {
    private List<String> myList;

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

oraz w odpowiednich metodach wywołaj myList.foo()zamiast this.foo()(lub super.foo()). (To nie pasuje do wszystkich przypadków, ale wciąż dość często.)

Często widzę osoby rozszerzające JFrame lub coś takiego, kiedy tak naprawdę muszą tylko to delegować. (Pomaga to również w automatycznym uzupełnianiu w środowisku IDE, ponieważ JFrame ma setki metod, których nie potrzebujesz, gdy chcesz wywoływać swoje niestandardowe w klasie).

Jednym z przypadków, w których ostrzeżenie (lub serialVersionUID) jest nieuniknione, jest to, że po wyjściu z AbstractAction, zwykle w klasie anonimowej, dodaje się tylko metodę actionPerformed-method. Myślę, że w tym przypadku nie powinno być ostrzeżenia (ponieważ normalnie nie można w sposób wiarygodny serializować i deserializować takich anonimowych klas w różnych wersjach klasy), ale nie jestem pewien, w jaki sposób kompilator mógłby to rozpoznać.

Paŭlo Ebermann
źródło
4
Myślę, że masz rację, że kompozycja zamiast nieuczciwości ma większy sens, szczególnie gdy omawiasz takie zajęcia, jak ArrayList. Jednak wiele frameworków wymaga od ludzi rozszerzania się od abstrakcyjnych nadklas, które można serializować (takich jak klasa ActionForm w Struts 1.2 lub Saxon's ExtensionFunctionDefinition), w którym to przypadku jest to niemożliwe. Myślę, że masz rację, byłoby miło, gdyby ostrzeżenie zostało zignorowane w niektórych przypadkach (na przykład, jeśli
wychodziłeś
2
Z pewnością, jeśli dodasz klasę jako element członkowski, zamiast dziedziczenia po niej, będziesz musiał napisać metodę otoki dla KAŻDEJ metody klasy członkowskiej, której chciałbyś użyć, co uniemożliwiłoby jej zastosowanie w wielu sytuacjach. , chyba że java ma funkcję podobną do Perla __AUTOLOAD, o której nie wiem.
M_M,
4
@M_M: Gdyby delegować wiele metod do zawiniętego obiektu, oczywiście niewłaściwe byłoby użycie delegowania. Ale przypuszczam, że ten przypadek jest oznaką błędu projektowego - użytkownicy twojej klasy (np. „MainGui”) nie powinni musieć wywoływać wielu metod zawiniętego obiektu (np. JFrame).
Paŭlo Ebermann
1
To, co mi się nie podoba w delegowaniu, to konieczność posiadania odniesienia do delegata. A każde odniesienie oznacza więcej pamięci. Popraw mnie, jeśli się mylę. Jeśli potrzebuję CustomizedArrayList 100 obiektów, nie będzie to miało większego znaczenia, ale jeśli potrzebuję setek CustomizdeArrayList kilku obiektów, użycie pamięci znacznie wzrasta.
WVrock
2
Throwable jest możliwe do serializacji, a tylko Throwable jest możliwe do rzucania, więc nie można zdefiniować wyjątku, który nie jest możliwy do serializacji. Delegacja nie jest możliwa.
Phil
22

Aby zrozumieć znaczenie pola serialVersionUID, należy zrozumieć, jak działa serializacja / deserializacja.

Gdy szeregowany obiekt klasy jest serializowany Java Runtime kojarzy numer seryjny (zwany jako serialVersionUID) z tym serializowanym obiektem. W chwili deserializacji tego serializowanego obiektu Java Runtime dopasowuje serialVersionUID serializowanego obiektu do serialVersionUID klasy. Jeśli oba są równe, to tylko dalszy proces deserializacji spowoduje zgłoszenie wyjątku InvalidClassException.

Stwierdzamy zatem, że aby proces serializacji / deserializacji zakończył się sukcesem, serialVersionUID obiektu serializowanego musi być równoważny serialVersionUID klasy. W przypadku, gdy programista wyraźnie określi wartość serialVersionUID w programie, wówczas ta sama wartość zostanie skojarzona z serializowanym obiektem i klasą, niezależnie od platformy serializacji i deserializacji (np. Serializacja może być wykonana na platformie takiej jak Windows za pomocą sun lub MS JVM i deserializacja mogą znajdować się na innej platformie Linux przy użyciu Zing JVM).

Jednak w przypadku, gdy programista nie określi serialVersionUID, wówczas podczas wykonywania Serialization \ DeSerialization dowolnego obiektu środowisko wykonawcze Java wykorzystuje własny algorytm do jego obliczenia. Ten algorytm obliczeniowy serialVersionUID różni się w zależności od środowiska JRE. Możliwe jest również, że środowisko, w którym obiekt jest szeregowany, używa jednego środowiska JRE (np. SUN JVM), a środowisko, w którym odbywa się deserializacja, używa środowiska Linux Jvm (zing). W takich przypadkach serialVersionUID skojarzony z serializowanym obiektem będzie inny niż serialVersionUID klasy obliczonej w środowisku deserializacji. Z kolei deserializacja nie powiedzie się. Aby uniknąć takich sytuacji / problemów, programista musi zawsze określać serialVersionUID klasy Serializable.

Nitesh Soni
źródło
2
Algorytm nie zmienia się, ale jest nieco niedokładny.
user207421
... algorytm nie zmienia się, ale jest nieco niedokładny ... co oznacza, że ​​każdy JVM może się różnić ..... @ user207421
AnthonyJClink
18

Nie przejmuj się, domyślna kalkulacja jest naprawdę dobra i wystarcza na 99,9999% przypadków. A jeśli napotkasz problemy, możesz - jak już wspomniano - wprowadzić identyfikatory UID, gdy zajdzie taka potrzeba (co jest bardzo mało prawdopodobne)

Grand Johnson
źródło
2
Śmieci. Jest odpowiedni w przypadku, gdy klasa się nie zmieniła. Nie masz żadnych dowodów na poparcie „99,9999%”.
user207421,
18

Na przykład, gdy brakujący serialVersionUID może powodować problem:

Pracuję nad aplikacją Java EE, która składa się z modułu WWW korzystającego z EJBmodułu. Moduł WWW wywołuje EJBmoduł zdalnie i przekazuje argument, POJOktóry implementuje Serializablejako argument.

Ta POJO'sklasa została zapakowana w słoik EJB i wewnątrz własnego słoika w WEB-INF / lib modułu WWW. W rzeczywistości są tej samej klasy, ale kiedy pakuję moduł EJB, rozpakowuję słoik tego POJO, aby spakować go razem z modułem EJB.

Wezwanie do EJBnie powiodło się z poniższym wyjątkiem, ponieważ nie zadeklarowałem jego serialVersionUID:

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52
Henrique Ordine
źródło
16

Zwykle używam serialVersionUIDw jednym kontekście: gdy wiem, że opuszcza kontekst maszyny wirtualnej Java.

Wiedziałbym o tym, kiedy będę używać ObjectInputStreami ObjectOutputStreamdla mojej aplikacji lub jeśli wiem, że biblioteka / środowisko, którego używam, będzie z niego korzystać. SerialVersionID zapewnia, że ​​różne maszyny wirtualne Java o różnych wersjach lub dostawcy będą współpracować poprawnie lub jeśli będą przechowywane i pobierane poza maszyną wirtualną na przykładHttpSession dane sesji mogą pozostać nawet podczas ponownego uruchomienia i aktualizacji serwera aplikacji.

We wszystkich innych przypadkach używam

@SuppressWarnings("serial")

ponieważ przez większość czasu ustawienie domyślne serialVersionUIDjest wystarczające. Obejmuje to Exception, HttpServlet.

Archimedes Trajano
źródło
Nie obejmuje HttpServlet w kontenerach, w których można je zamienić, ani na przykład wyjątku w RMI.
user207421
14

Dane pola reprezentują niektóre informacje przechowywane w klasie. Klasa implementuje Serializableinterfejs, więc zaćmienie automatycznie proponuje deklarację serialVersionUIDpola. Zacznijmy od ustawionej tam wartości 1.

Jeśli nie chcesz, aby pojawiło się to ostrzeżenie, użyj tego:

@SuppressWarnings("serial")
Mukti
źródło
11

Byłoby miło, gdyby CheckStyle mógł zweryfikować, czy serialVersionUID w klasie, która implementuje Serializable, ma dobrą wartość, tj. Czy pasuje do tego, co wygenerowałby generator id wersji seryjnej. Jeśli masz projekt z wieloma serializowalnymi DTO, na przykład pamiętaj, aby usunąć istniejący serialVersionUID i zregenerować go, jest to ból, a obecnie jedynym sposobem (o którym wiem), aby to zweryfikować, jest regeneracja dla każdej klasy i porównanie z ten stary. To bardzo, bardzo bolesne.


źródło
8
Jeśli ustawisz serialVersionUID zawsze na tę samą wartość, którą generowałby generator, tak naprawdę wcale go nie potrzebujesz. W końcu jego raison d'être ma pozostać taki sam po zmianach, gdy klasa jest nadal kompatybilna.
Paŭlo Ebermann
4
Powodem jest to, że różne kompilatory mają tę samą wartość dla tej samej klasy. Jak wyjaśniono w javadocs (na które również odpowiedziano powyżej), wygenerowana wersja jest krucha i może się różnić, nawet jeśli klasa jest odpowiednio deserializowalna. Tak długo, jak uruchamiasz ten test za każdym razem na tym samym kompilatorze, powinien on być bezpieczny. niech Bóg ci pomoże, jeśli zaktualizujesz jdk i pojawi się nowa reguła, nawet jeśli kod się nie zmienił.
Andrew Backer,
2
Nie jest wymagane dopasowanie tego serialver, co by wyprodukowało. -1
207421
Ogólnie nie jest to wcale wymagane. @ Przypadek AndrewBackera wymagałby dwóch różnych kompilatorów w tym samym pliku .java, a obie wersje plików .class komunikowałyby się ze sobą - przez większość czasu po prostu tworzysz klasę i rozpowszechniasz ją. W takim przypadku brak identyfikatora SUID działałby dobrze.
Bill K
1
Ludzie, którzy naprawdę używają serializacji do celów przechowywania / pobierania, zazwyczaj ustawiają wartość serialVersionUID1. Jeśli nowsza wersja klasy jest niezgodna, ale nadal wymaga obsługi starych danych, zwiększasz numer wersji i dodajesz specjalny kod do radzić sobie ze starszymi formatami. Płaczę za każdym razem, gdy widzę serialVersionUIDwięcej niż 1 cyfrę, albo dlatego, że była to liczba losowa (bezużyteczna), albo dlatego, że klasa najwyraźniej musi poradzić sobie z ponad 10 różnymi wersjami.
john16384
11

SerialVersionUID służy do kontroli wersji obiektu. możesz również podać serialVersionUID w pliku klasy. Konsekwencją braku określenia serialVersionUID jest to, że po dodaniu lub zmodyfikowaniu dowolnego pola w klasie już zserializowana klasa nie będzie w stanie odzyskać, ponieważ serialVersionUID wygenerowany dla nowej klasy i dla starego serializowanego obiektu będzie inny. Proces serializacji Java opiera się na poprawnym identyfikatorze serialVersionUID w celu odzyskania stanu obiektu serializowanego i zgłasza wyjątek java.io.InvalidClassException w przypadku niezgodności serialVersionUID

Czytaj więcej: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ

Neethu
źródło
9

Po co używać klasy SerialVersionUIDwewnętrznej Serializablew Javie?

Podczas serializationdziałania środowiska wykonawczego Java tworzony jest numer wersji dla klasy, aby można go później przekształcić do postaci szeregowej. Ten numer wersji jest znany jako SerialVersionUIDJava.

SerialVersionUIDsłuży do wersji danych zserializowanych. Możesz usunąć serializację klasy tylko wtedy, gdy jestSerialVersionUID zgodna z serializowaną instancją. Gdy nie deklarujemy SerialVersionUIDw naszej klasie, środowisko wykonawcze Java generuje je dla nas, ale nie jest to zalecane. Zaleca się deklarowanie SerialVersionUIDjako private static final longzmiennej, aby uniknąć domyślnego mechanizmu.

Gdy deklarujesz klasę jako Serializableimplementując interfejs znacznika java.io.Serializable, środowisko wykonawcze Java zachowuje instancję tej klasy na dysku za pomocą domyślnego mechanizmu serializacji, pod warunkiem, że nie dostosowałeś procesu za pomocą Externalizableinterfejsu.

zobacz także Dlaczego warto korzystać z SerialVersionUID w klasie Serializable w Javie

Kod: javassist.SerialVersionUID

roottraveller
źródło
8

Jeśli chcesz zmienić ogromną liczbę klas, dla których nie ustawiono serialVersionUID, jednocześnie zachowując kompatybilność ze starymi klasami, narzędzia takie jak IntelliJ Idea, Eclipse są niewystarczające, ponieważ generują losowe liczby i nie działają na zbiorze plików za jednym razem. Pojawiam się następujący skrypt bash (przepraszam dla użytkowników systemu Windows, rozważ zakup Maca lub konwersję do Linuksa), aby łatwo zmienić problem serialVersionUID:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print $_; printf qq{%s\n}, q{    private $seruidstr} if /public class/" $src_dir/$f
done

zapisz ten skrypt, powiedz do ciebie add_serialVersionUID.sh ~ / bin. Następnie uruchom go w katalogu głównym projektu Maven lub Gradle, np .:

add_serialVersionUID.sh < myJavaToAmend.lst

Ten plik .lst zawiera listę plików Java, aby dodać serialVersionUID w następującym formacie:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

Ten skrypt używa narzędzia JDK serialVer pod maską. Upewnij się więc, że Twój $ JAVA_HOME / bin znajduje się w ŚCIEŻCE.

schnell18
źródło
2
Daje mi pomysł: zawsze generuj identyfikator UID wersji seryjnej za pomocą takiego narzędzia, nigdy ręcznie, przed wydaniem wydania - w ten sposób unikniesz zmiany w klasie, której identyfikator UID powinien zostać zmieniony z powodu faktycznego niezgodna zmiana. Ręczne śledzenie tego jest bardzo trudne.
Ignazio,
6

To pytanie jest bardzo dobrze udokumentowane w Effective Java autorstwa Joshua Bloch. Bardzo dobra książka i trzeba ją przeczytać. Przedstawię niektóre z poniższych przyczyn:

Środowisko wykonawcze serializacji zawiera liczbę o nazwie Wersja szeregowa dla każdej klasy możliwej do serializacji. Ten numer nazywa się serialVersionUID. Teraz za tą liczbą kryje się trochę matematyki, która wychodzi na podstawie pól / metod zdefiniowanych w klasie. Dla tej samej klasy za każdym razem generowana jest ta sama wersja. Liczba ta jest używana podczas deserializacji w celu sprawdzenia, czy nadawca i odbiorca obiektu serializowanego załadowali klasy dla tego obiektu, które są kompatybilne w odniesieniu do serializacji. Jeśli odbiorca załadował klasę dla obiektu, który ma inny identyfikator serialVersionUID niż klasy odpowiedniego nadawcy, deserializacja spowoduje wyjątek InvalidClassException.

Jeśli klasa jest serializowalna, możesz również jawnie zadeklarować własny serialVersionUID, deklarując pole o nazwie „serialVersionUID”, które musi być statyczne, końcowe i mieć długi typ. Większość IDE, takich jak Eclipse, pomaga wygenerować ten długi ciąg.

Maniak
źródło
6

Za każdym razem, gdy obiekt jest szeregowany, obiekt jest stemplowany numerem identyfikacyjnym wersji dla klasy obiektu. Ten identyfikator nazywa się serialVersionUID i jest obliczany na podstawie informacji o strukturze klasy. Załóżmy, że utworzyłeś klasę Employee i ma ona wersję nr 333 (przypisaną przez JVM). Teraz, kiedy serializujesz obiekt tej klasy (Załóżmy, że obiekt pracownika), JVM przypisze mu identyfikator UID jako # 333.

Rozważ sytuację - w przyszłości musisz edytować lub zmienić klasę, a w takim przypadku, gdy ją zmodyfikujesz, JVM przypisze jej nowy UID (Załóżmy, że # 444). Teraz, gdy spróbujesz deserializować obiekt pracownika, JVM porówna identyfikator wersji obiektu szeregowego (obiekt pracownika) (# 333) z identyfikatorem klasy, tj. # 444 (ponieważ został zmieniony). Dla porównania JVM wykryje, że obie wersje UID są różne, a zatem deserializacja zakończy się niepowodzeniem. Dlatego jeśli serialVersionID dla każdej klasy jest zdefiniowany przez samego programistę. Będzie tak samo, nawet jeśli klasa będzie ewoluować w przyszłości, a zatem JVM zawsze stwierdzi, że klasa jest kompatybilna z serializowanym obiektem, nawet jeśli klasa zostanie zmieniona. Więcej informacji można znaleźć w rozdziale 14 HEAD FIRST JAVA.

Naved Ali
źródło
1
Za każdym razem, gdy klasa obiektu jest szeregowana, serialVersionUIDprzesyłany jest. Nie jest wysyłany z każdym obiektem.
user207421,
3

Proste wyjaśnienie:

  1. Czy serializujesz dane?

    Serializacja polega zasadniczo na zapisywaniu danych klasy do pliku / strumienia / etc. Dezserializacja polega na odczytywaniu tych danych z powrotem do klasy.

  2. 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ę).

  3. Czy to jest pierwsza wersja?

    Jeśli tak, ustaw serialVersionUID=1L.

  4. Czy to druga, trzecia itd. Wersja produktu?

    Teraz musisz się martwić serialVersionUIDi zagłębić się w to.

Zasadniczo, jeśli nie zaktualizujesz wersji poprawnie podczas aktualizacji klasy, musisz zapisać / odczytać, pojawi się błąd przy próbie odczytania starych danych.

gagarwa
źródło
2

„serialVersionUID” to 64-bitowa liczba używana do jednoznacznej identyfikacji klasy podczas procesu deserializacji. Podczas serializacji obiektu serialVersionUID klasy również jest zapisywany w pliku. Ilekroć deserializujesz ten obiekt, java w czasie wykonywania wyodrębnia tę wartość serialVersionUID z danych serializowanych i porównuje tę samą wartość skojarzoną z klasą. Jeśli oba się nie zgadzają, zostanie wygenerowany wyjątek „java.io.InvalidClassException”.

Jeśli klasa możliwa do serializacji nie zadeklaruje jawnie serialVersionUID, środowisko wykonawcze serializacji obliczy wartość serialVersionUID dla tej klasy w oparciu o różne aspekty klasy, takie jak pola, metody itp. ,, Możesz skorzystać z tego łącza do aplikacji demonstracyjnej.

Hari Krishna
źródło
1

Krótko mówiąc, to pole służy do sprawdzania, czy dane zserializowane mogą być poprawnie przekształcone z postaci szeregowej. Serializacja i deserializacja są często wykonywane przez różne kopie programu - na przykład serwer konwertuje obiekt na ciąg, a klient konwertuje otrzymany ciąg na obiekt. To pole mówi, że oba działają z takim samym wyobrażeniem o tym, czym jest ten obiekt. To pole pomaga, gdy:

  • masz wiele różnych kopii swojego programu w różnych miejscach (np. 1 serwer i 100 klientów). Jeśli zmienisz obiekt, zmienisz numer wersji i zapomnisz zaktualizować jednego z tych klientów, będzie wiedział, że nie jest on w stanie dokonać deserializacji

  • zapisałeś swoje dane w jakimś pliku, a później próbujesz go otworzyć za pomocą zaktualizowanej wersji programu ze zmodyfikowanym obiektem - będziesz wiedział, że ten plik nie jest kompatybilny, jeśli utrzymasz odpowiednią wersję

Kiedy to jest ważne

Najbardziej oczywiste - jeśli dodasz niektóre pola do swojego obiektu, starsze wersje nie będą mogły ich używać, ponieważ nie mają tych pól w strukturze obiektu.

Mniej oczywiste - po deserializacji obiektu pola, które nie są obecne w ciągu, będą zachowane jako NULL. Jeśli usunąłeś pole ze swojego obiektu, starsze wersje zachowają to pole jako zawsze NULL, co może prowadzić do złego zachowania, jeśli starsze wersje polegają na danych w tym polu (w każdym razie stworzyłeś je dla czegoś, nie tylko dla zabawy :-))

Najmniej oczywiste - czasami zmieniasz pomysł, który nadałeś sensowi jakiegoś pola. Na przykład, kiedy masz 12 lat, pod „rowerem” masz na myśli „rower”, ale kiedy masz 18 lat, masz na myśli „motocykl” - jeśli Twoi znajomi zaprosą Cię na „przejażdżkę rowerem po mieście” i będziesz jedynym, który przyszedł na rower, nie zrozumiesz, jak ważne jest zachowanie tego samego znaczenia na różnych polach :-)

Stanisław Orłow
źródło
1

Po pierwsze, aby odpowiedzieć na twoje pytanie, kiedy nie deklarujemy SerialVersionUID w naszej klasie, środowisko wykonawcze Java generuje je dla nas, ale ten proces jest wrażliwy na wiele metadanych klasy, w tym liczbę pól, rodzaj pól, modyfikator dostępu do pól, zaimplementowany interfejs według klas itp. Dlatego zaleca się, aby zadeklarować to sami, a Eclipse ostrzega o tym samym.

Serializacja: Często pracujemy z ważnymi obiektami, których stan (dane w zmiennych obiektu) jest tak ważny, że nie możemy ryzykować jego utraty z powodu awarii zasilania / systemu (lub) awarii sieci w przypadku wysłania stanu obiektu do innego maszyna. Rozwiązanie tego problemu nosi nazwę „Trwałość”, co oznacza po prostu utrwalanie (przechowywanie / zapisywanie) danych. Serializacja jest jednym z wielu innych sposobów osiągnięcia trwałości (poprzez zapisanie danych na dysku / pamięci). Podczas zapisywania stanu obiektu ważne jest, aby utworzyć tożsamość obiektu, aby móc go poprawnie odczytać (deserializacja). Ta unikalna identyfikacja to ID to SerialVersionUID.

Shanks D Shiva
źródło
0

Co to jest SerialVersionUID? Odpowiedź: - Powiedzmy, że są dwie osoby, jedna z centrali, a druga z ODC, obie będą odpowiednio wykonywać serializację i deserializację. W tym przypadku w celu uwierzytelnienia, że ​​odbiorca będący w ODC jest osobą uwierzytelnioną, JVM tworzy unikalny identyfikator, który jest znany jako SerialVersionUID.

Oto dobre wyjaśnienie na podstawie scenariusza,

Dlaczego SerialVersionUID?

Serializacja : w momencie serializacji JVM zapisuje unikalny identyfikator dla każdej strony wysyłającej obiekt. JVM jest odpowiedzialny za wygenerowanie tego unikalnego identyfikatora na podstawie odpowiedniego pliku .class, który jest obecny w systemie nadawcy.

Deserializacja : w czasie deserializacji JVM po stronie odbiorcy porówna unikalny identyfikator powiązany z obiektem z unikalnym identyfikatorem klasy lokalnej, tj. JVM utworzy również unikalny identyfikator na podstawie odpowiedniego pliku .class, który jest obecny w systemie odbiorczym. Jeśli oba unikalne identyfikatory są dopasowane, zostanie przeprowadzona tylko deserializacja. W przeciwnym razie otrzymamy wyjątek Runtime Exception z informacją InvalidClassException. Ten unikalny identyfikator jest niczym innym jak SerialVersionUID

widelec
źródło