Vraag Wat is een serialVersionUID en waarom zou ik het gebruiken?


Eclipse geeft waarschuwingen als a serialVersionUID ontbreekt.

De serialiseerbare klasse Foo geeft geen statische finale aan   serialVersionUID veld van type long

Wat is serialVersionUID en waarom is het belangrijk? Geef een voorbeeld als ontbrekend serialVersionUID veroorzaakt een probleem.


2482
2017-11-12 23:24


oorsprong


antwoorden:


De documentatie voor java.io.Serializable zijn waarschijnlijk ongeveer net zo goed een uitleg als je krijgt:

De runtime voor serialisatie komt overeen   bij elke serialiseerbare klasse een versie   nummer, een serialVersionUID genaamd,   die wordt gebruikt tijdens deserialisatie   om te verifiëren dat de zender en ontvanger   van een geserialiseerd object zijn geladen   klassen voor dat object die dat wel zijn   compatibel met respect voor   serialisatie. Als de ontvanger heeft   geladen een klasse voor het object dat heeft   een andere serialVersionUID dan dat   van de corresponderende afzenderklasse,   dan zal deserialisatie resulteren in een    InvalidClassException. Een serialiseerbaar   klasse kan zijn eigen verklaren   serialVersionUID expliciet door   een veld met de naam declareren   "serialVersionUID" dat moet zijn   statisch, definitief en van het type long:

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

Als een   serializable-klasse niet expliciet   een serialVersionUID en vervolgens de   serialisatie runtime berekent a   standaard serialVersionUID-waarde voor   die klasse op basis van verschillende aspecten van   de klasse, zoals beschreven in de   Java (TM) Object-serialisatie   Specificatie. Hoe het ook is sterk   aanbevolen die allemaal serialiseerbaar zijn   klassen expliciet verklaren   serialVersionUID-waarden, omdat de   standaard serialVersionUID-berekening   is zeer gevoelig voor klassegegevens   dat kan variëren afhankelijk van de compiler   implementaties, en kan dus resulteren   onverwacht InvalidClassExceptions   tijdens deserialisatie. Daarom, om   een consistent garanderen   serialVersionUID-waarde over   verschillende Java-compiler   implementaties, een serialiseerbare klasse   moet een expliciet verklaren   serialVersionUID-waarde. Het is ook   sterk aanbevolen dat expliciet   serialVersionUID-verklaringen gebruiken de   private modifier waar mogelijk, sinds   dergelijke verklaringen zijn alleen van toepassing op de   onmiddellijk verklaren   class - serialVersionUID-velden zijn dat niet   nuttig als geërfde leden.


1910
2017-11-12 23:30



Als je serialiseert, alleen maar omdat je moet serialiseren omwille van de implementatie (who cares of je serialiseert voor een HTTPS-sessie, bijvoorbeeld ... als het is opgeslagen of niet, geef je waarschijnlijk niet om het de-serialiseren van een formulier-object) , dan kun je dit negeren.

Als u daadwerkelijk serialisatie gebruikt, is het alleen van belang als u van plan bent objecten rechtstreeks op te slaan en op te halen met behulp van serialisatie. De serialVersionUID vertegenwoordigt uw klasse-versie en u moet deze verhogen als de huidige versie van uw klasse niet achterwaarts compatibel is met de vorige versie.

Meestal zult u de serialisatie waarschijnlijk niet rechtstreeks gebruiken. Als dit het geval is, genereert u een standaard serialiseerbare uid door op de optie quick fix te klikken en maakt u zich daar geen zorgen over.


415
2017-11-13 04:24



Ik kan deze gelegenheid niet voorbij laten gaan om Josh Bloch's boek te sluiten Effectieve Java (2e editie). Hoofdstuk 11 is een onmisbare hulpbron voor Java-serialisatie.

Per Josh wordt de automatisch gegenereerde UID gegenereerd op basis van een klassenaam, geïmplementeerde interfaces en alle openbare en beschermde leden. Het wijzigen van een van deze op welke manier dan ook zal de serialVersionUID. U hoeft dus niet alleen met ze te morrelen als u er zeker van bent dat niet meer dan één versie van de klasse ooit geserialiseerd zal worden (hetzij over processen heen, hetzij op een later tijdstip uit de opslag gehaald).

Als je ze voor nu negeert en later vindt dat je de klasse op een of andere manier moet wijzigen, maar de compatibiliteit met de oude versie van de klasse moet behouden, kun je de JDK-tool gebruiken serialver om de te genereren serialVersionUID op de oud klasse, en expliciet dat in de nieuwe klasse. (Afhankelijk van uw wijzigingen moet u mogelijk ook aangepaste serialisatie implementeren door deze toe te voegen writeObject en readObject methoden - zie Serializable javadoc of eerder genoemd hoofdstuk 11.)


264
2017-11-12 23:37



U kunt Eclipse vertellen om deze serialVersionUID-waarschuwingen te negeren:

Venster> Voorkeuren> Java> Compiler> Fouten / Waarschuwingen> Potentiële programmeerproblemen

In het geval dat u het nog niet wist, zijn er veel andere waarschuwingen die u in deze sectie kunt inschakelen (of zelfs hebt gerapporteerd als fouten), veel zijn erg handig:

  • Potentiële programmeerproblemen: mogelijke toevallige booleaanse toewijzing
  • Potentiële programmeerproblemen: Null pointer-toegang
  • Onnodige code: Lokale variabele wordt nooit gelezen
  • Onnodige code: overbodige nulcontrole
  • Onnodige code: onnodige cast of 'instanceof'

en nog veel meer.


124
2017-11-13 01:17



serialVersionUID faciliteert versiebeheer van geserialiseerde gegevens. De waarde wordt opgeslagen met de gegevens bij het serialiseren. Bij het de-serialiseren wordt dezelfde versie gecontroleerd om te zien hoe de geserialiseerde gegevens overeenkomen met de huidige code.

Als u uw gegevens wilt verversen, begint u normaal met een serialVersionUID van 0, en gooi het met elke structurele wijziging in uw klasse die de geserialiseerde gegevens wijzigt (niet-transiënte velden toevoegen of verwijderen).

Het ingebouwde de-serialisatie mechanisme (in.defaultReadObject()) zal weigeren te de-serialiseren van oude versies van de gegevens. Maar als u wilt kunt u uw eigen definiëren readObject ()-functie die oude gegevens kan teruglezen. Deze aangepaste code kan dan de serialVersionUID om te weten in welke versie de gegevens zich bevinden en om te beslissen hoe u de seriële de-serialisatie ervan gebruikt. Deze versie-aanpassingstechniek is handig als u geserialiseerde gegevens opslaat die verschillende versies van uw code overleeft.

Maar het opslaan van geserialiseerde gegevens gedurende zo'n lange tijdsspanne is niet erg gebruikelijk. Het is veel gebruikelijker om het serialisatiemechanisme te gebruiken om tijdelijk gegevens te schrijven naar bijvoorbeeld een cache of deze over het netwerk te verzenden naar een ander programma met dezelfde versie van de relevante delen van de codebase.

In dit geval bent u niet geïnteresseerd in het handhaven van compatibiliteit met eerdere versies. U bent alleen bezig met ervoor te zorgen dat de codebasen die communiceren inderdaad dezelfde versies van relevante klassen hebben. Om een ​​dergelijke controle mogelijk te maken, moet u de serialVersionUIDnet als voorheen en vergeet niet om het bij te werken bij het aanbrengen van wijzigingen in uw klassen.

Als u vergeet het veld bij te werken, zou u kunnen eindigen met twee verschillende versies van een klasse met een andere structuur maar met dezelfde serialVersionUID. Als dit gebeurt, is het standaardmechanisme (in.defaultReadObject()) detecteert geen verschil en probeert incompatibele gegevens te de-serialiseren. Nu kunt u eindigen met een cryptische runtime-fout of stille fout (nul-velden). Dit soort fouten is misschien moeilijk te vinden.

Om deze usecase te helpen, biedt het Java-platform u de keuze om de serialVersionUID handmatig. In plaats daarvan wordt tijdens het compileren een hash van de klassenstructuur gegenereerd en als ID gebruikt. Dit mechanisme zorgt ervoor dat u nooit verschillende klassenstructuren met dezelfde id hebt, en dus krijgt u deze moeilijk te traceren runtime-serialisatiefouten die hierboven zijn vermeld, niet.

Maar er is een keerzijde aan de automatisch gegenereerde id-strategie. Namelijk dat de gegenereerde ID's voor dezelfde klasse kunnen verschillen tussen compilers (zoals eerder genoemd door Jon Skeet). Dus als u geserialiseerde gegevens communiceert tussen code die is gecompileerd met verschillende compilers, is het aan te raden de id's toch handmatig te handhaven.

En als je backward-compatibel bent met je gegevens zoals in de genoemde eerste use-case, wil je waarschijnlijk ook de id zelf behouden. Dit om leesbare id's te krijgen en meer controle te hebben over wanneer en hoe ze veranderen.


96
2017-10-03 06:05



Wat is een serialVersionUID en waarom zou ik het gebruiken?

SerialVersionUID is een unieke identificatie voor elke klasse, JVM gebruikt het om de versies van de klasse te vergelijken en ervoor te zorgen dat dezelfde klasse werd gebruikt tijdens serialisatie wordt geladen tijdens deserialisatie.

Het opgeven van een geeft meer controle, hoewel JVM er een genereert als u niet opgeeft. De gegenereerde waarde kan verschillen tussen verschillende compilers. Bovendien wil je soms om een ​​of andere reden deserialisatie van oude geserialiseerde objecten verbieden [backward incompatibility], en in dit geval hoeft u alleen de serialVersionUID te wijzigen.

De javadocs voor Serializable zeggen:

de standaard serialVersionUID-berekening is zeer gevoelig voor klasse   details die kunnen variëren afhankelijk van de implementaties van de compilator, en kunnen   dus resulteren in onverwacht InvalidClassExceptions tijdens   deserialisatie.

Daarom moet u serialVersionUID declareren omdat dit ons meer controle geeft.

Dit artikel heeft een aantal goede punten over het onderwerp.


62
2017-10-17 04:28



De oorspronkelijke vraag heeft gevraagd: 'waarom is het belangrijk' en 'voorbeeld' waar dit Serial Version ID zou nuttig zijn. Nou ik heb er een gevonden.

Stel dat je een maakt Car class, maak een instantiate en schrijf het uit naar een objectstream. Het afgeplatte auto-object bevindt zich al enige tijd in het bestandssysteem. Ondertussen, als het Car klasse wordt gewijzigd door een nieuw veld toe te voegen. Later, wanneer u de afgevlakte probeert te lezen (d.w.z. deserialize) Car object, je krijgt de java.io.InvalidClassException - omdat alle serialiseerbare klassen automatisch een unieke identificatie krijgen. Deze uitzondering wordt gegenereerd wanneer de ID van de klasse niet gelijk is aan de ID van het afgeplatte object. Als je er echt over nadenkt, wordt de uitzondering gegenereerd door de toevoeging van het nieuwe veld. U kunt voorkomen dat deze uitzondering wordt gegenereerd door de versiebeheer zelf te regelen door een expliciete serialVersionUID te declareren. Er is ook een klein prestatie-voordeel door uw expliciet te verklaren serialVersionUID(omdat hoeft niet te worden berekend). Het is dus het beste om uw eigen serialVersionUID toe te voegen aan uw Serializable-klassen zodra u ze maakt, zoals hieronder wordt weergegeven:

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

41
2018-04-07 10:43



Als je deze waarschuwing krijgt in een klas, denk je nooit aan serialisatie, en dat je jezelf niet hebt verklaard implements Serializable, het komt vaak omdat je hebt geërfd van een superklasse, die Serializable implementeert. Vaak is het dan beter om te delegeren naar een dergelijk object in plaats van overerving te gebruiken.

Dus in plaats van

public class MyExample extends ArrayList<String> {

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

do

public class MyExample {
    private List<String> myList;

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

en in de relevante methoden bellen myList.foo() in plaats van this.foo() (of super.foo()). (Dit past niet in alle gevallen, maar nog steeds vrij vaak.)

Ik zie vaak mensen die JFrame uitbreiden of zo, wanneer ze dit echt alleen maar moeten delegeren. (Dit helpt ook bij het automatisch aanvullen in een IDE, aangezien JFrame honderden methoden heeft, die je niet nodig hebt als je je aangepaste degenen in je klas wilt aanroepen.)

Een geval waarbij de waarschuwing (of de serialVersionUID) onvermijdelijk is, is wanneer u zich uitbreidt van AbstractAction, normaal gesproken in een anonieme klasse, waarbij alleen de actionPerformed-methode wordt toegevoegd. Ik denk dat er in dit geval geen waarschuwing zou moeten zijn (aangezien je normaal gesproken niet betrouwbaar dergelijke seriële klassen kunt serialize en deserialiseren over verschillende versies van je klas), maar ik weet niet zeker hoe de compiler dit zou kunnen herkennen.


33
2018-02-03 00:32



Als u uw objecten nooit hoeft te serialiseren naar bytearray en deze wilt verzenden / opslaan, hoeft u zich daar geen zorgen over te maken. Als dat het geval is, moet u rekening houden met uw serialVersionUID, omdat de deserializer van het object overeenkomt met de versie van het object dat zijn classloader heeft. Lees er meer over in de Java-taalspecificatie.


30
2017-11-12 23:30



Om de betekenis van veldserieversionUID te begrijpen, moet men begrijpen hoe serialisatie / deserialisatie werkt.

Wanneer een Serializable-klasseobject in serie wordt geplaatst, koppelt Java Runtime een serieel versienummer (genoemd als serialVersionUID) aan dit seriedragende object. Op het moment dat u dit geserialiseerde object deserialiseert, komt Java Runtime overeen met de serialVersionUID van geserialiseerd object met de serialVersionUID van de klasse. Als beide gelijk zijn, gaat alleen het verder met het verdere proces van deserialisatie en werpt Anders InvalidClassException.

Dus concluderen we dat om het serialisatie / deserialisatieproces succesvol te laten zijn, de serialVersionUID van geserialiseerd object equivalent moet zijn aan de serialVersionUID van de klasse. Als de programmeur expliciet in het programma de waarde serialVersionUID opgeeft, wordt dezelfde waarde gekoppeld aan het object in serie en de klasse, ongeacht het serialisatie- en deserialzatieplatform (bijvoorbeeld serialisatie kan op een platform worden uitgevoerd zoals vensters door gebruik te maken van zon of MS JVM en deserialisatie kunnen op verschillende platforms Linux zijn met behulp van Zing JVM).

Maar in het geval dat serialVersionUID niet is opgegeven door de programmeur, terwijl tijdens het uitvoeren van serialisatie \ DeSerialization van een willekeurig object, Java-runtime zijn eigen algoritme gebruikt om het te berekenen. Dit berekeningsalgoritme voor serialVersionUID varieert van JRE tot andere. Het is ook mogelijk dat de omgeving waarin het object geserialiseerd wordt, één JRE gebruikt (bijv .: SUN JVM) en de omgeving waarin deserialisatie plaatsvindt, Linux Jvm (zing) gebruikt. In dergelijke gevallen zal serialVersionUID in combinatie met een geserialiseerd object anders zijn dan de serialVersionUID van klasse die is berekend in de deserialzation-omgeving. Op zijn beurt zal deserialisatie niet succesvol zijn. Dus om dergelijke situaties / problemen te voorkomen, moet programmeur altijd serialVersionUID van de Serializable-klasse opgeven.


19
2018-06-02 06:20



Doe geen moeite, de standaardberekening is echt goed en volstaat voor 99,9999% van de gevallen. En als je problemen tegenkomt, kun je - zoals gezegd - UID's introduceren als de noodzaak (dit is hoogst onwaarschijnlijk)


18
2018-04-29 15:59