Inleiding tot Java-serialisering

1. Inleiding

Serialisatie is de omzetting van de toestand van een object in een bytestroom; deserialisatie doet het tegenovergestelde. Anders gezegd, serialisatie is de omzetting van een Java-object in een statische stroom (reeks) bytes die vervolgens kan worden opgeslagen in een database of via een netwerk kan worden overgedragen.

2. Serialisatie en deserialisering

Het serialisatieproces is instantie-onafhankelijk, d.w.z. objecten kunnen op het ene platform worden geserialiseerd en op een ander gedeserialiseerd. Klassen die in aanmerking komen voor serialisatie, moeten een speciale markeringsinterface implementerenSerialiseerbaar.

Beide ObjectInputStream en ObjectOutputStream zijn klassen op hoog niveau die zich uitstrekken java.io.InputStream en java.io.OutputStream respectievelijk. ObjectOutputStream kan primitieve typen en grafieken van objecten naar een OutputStream als een stroom bytes. Deze streams kunnen vervolgens worden uitgelezen met ObjectInputStream.

De belangrijkste methode in ObjectOutputStream is:

public final void writeObject (Object o) gooit IOException;

Dat neemt een serialiseerbaar object en converteert het naar een reeks (stroom) bytes. Evenzo is de belangrijkste methode in ObjectInputStream is:

public final Object readObject () gooit IOException, ClassNotFoundException;

Die een stroom bytes kan lezen en deze terug kan converteren naar een Java-object. Dit kan vervolgens worden teruggegoten naar het oorspronkelijke object.

Laten we de serialisatie illustreren met een Persoon klasse. Let daar op statische velden behoren tot een klasse (in tegenstelling tot een object) en zijn niet geserialiseerd. Merk ook op dat we het trefwoord kunnen gebruiken voorbijgaand klassevelden negeren tijdens serialisering:

public class Person implementeert Serializable {private static final long serialVersionUID = 1L; static String country = "ITALIË"; privé int leeftijd; private String naam; voorbijgaande int hoogte; // getters en setters}

De onderstaande test toont een voorbeeld van het opslaan van een type object Persoon naar een lokaal bestand en lees deze waarde vervolgens weer in:

@Test openbare leegte whenSerializingAndDeserializing_ThenObjectIsTheSame () () gooit IOException, ClassNotFoundException {Person person = new Person (); person.setAge (20); person.setName ("Joe"); FileOutputStream fileOutputStream = nieuwe FileOutputStream ("uwbestand.txt"); ObjectOutputStream objectOutputStream = nieuwe ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (persoon); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = nieuwe FileInputStream ("uwbestand.txt"); ObjectInputStream objectInputStream = nieuwe ObjectInputStream (fileInputStream); Persoon p2 = (Persoon) objectInputStream.readObject (); objectInputStream.close (); assertTrue (p2.getAge () == p.getAge ()); assertTrue (p2.getName (). is gelijk aan (p.getName ())); }

We gebruikten ObjectOutputStream voor het opslaan van de staat van dit object in een bestand met FileOutputStream. Het bestand "Uwbestand.txt" wordt aangemaakt in de projectdirectory. Dit bestand wordt vervolgens geladen met FileInputStream.ObjectInputStream pikt deze stream op en zet deze om in een nieuw object met de naam p2.

Ten slotte testen we de staat van het geladen object, en het komt overeen met de staat van het originele object.

Merk op dat het geladen object expliciet naar een Persoon type.

3. Voorbehouden voor Java-serialisering

Er zijn enkele kanttekeningen met betrekking tot de serialisatie in Java.

3.1. Overerving en samenstelling

Wanneer een klas het java.io.Serializable interface, kunnen al zijn subklassen ook worden geserialiseerd. Als een object daarentegen een verwijzing naar een ander object heeft, moeten deze objecten de Serialiseerbaar interface afzonderlijk, of anders een NotSerializableException zal worden gegooid:

public class Person implementeert Serializable {private int age; private String naam; privé adres land; // moet ook serialiseerbaar zijn} 

Als een van de velden in een serialiseerbaar object uit een reeks objecten bestaat, moeten al deze objecten ook serialiseerbaar zijn, of anders een NotSerializableException zal worden gegooid.

3.2. Seriële versie UID

De JVM associeert een versie (lang) nummer bij elke serialiseerbare klasse. Het wordt gebruikt om te controleren of de opgeslagen en geladen objecten dezelfde attributen hebben en dus compatibel zijn met serialisering.

Dit nummer kan automatisch worden gegenereerd door de meeste IDE's en is gebaseerd op de klassenaam, de attributen en bijbehorende toegangsmodificatoren. Elke wijziging resulteert in een ander nummer en kan een InvalidClassException.

Als een serialiseerbare klasse geen serialVersionUID, zal de JVM er automatisch een genereren tijdens runtime. Het wordt echter ten zeerste aanbevolen dat elke klasse zijn serialVersionUID aangezien de gegenereerde compilerafhankelijk is en dus kan resulteren in onverwachte InvalidClassExceptions.

3.3. Aangepaste serialisering in Java

Java specificeert een standaardmanier waarop objecten kunnen worden geserialiseerd. Java-klassen kunnen dit standaardgedrag opheffen. Aangepaste serialisering kan met name handig zijn wanneer u probeert een object te serialiseren dat een aantal niet-serialiseerbare attributen heeft. Dit kan worden gedaan door twee methoden aan te bieden binnen de klasse die we willen serialiseren:

private void writeObject (ObjectOutputStream out) gooit IOException;

en

private void readObject (ObjectInputStream in) gooit IOException, ClassNotFoundException;

Met deze methoden kunnen we die niet-serialiseerbare attributen serialiseren in andere vormen die kunnen worden geserialiseerd:

public class Medewerker implementeert Serializable {private static final long serialVersionUID = 1L; privé tijdelijk adres; particulier persoon; // setters en getters private void writeObject (ObjectOutputStream oos) gooit IOException {oos.defaultWriteObject (); oos.writeObject (adres.getHouseNumber ()); } private void readObject (ObjectInputStream ois) gooit ClassNotFoundException, IOException {ois.defaultReadObject (); Geheel getal houseNumber = (Geheel getal) ois.readObject (); Adres a = nieuw adres (); a.setHouseNumber (houseNumber); this.setAddress (a); }}
openbare klasse Adres {privé int houseNumber; // setters en getters}

De volgende eenheidstest test deze aangepaste serialisering:

@Test openbare leegte whenCustomSerializingAndDeserializing_ThenObjectIsTheSame () gooit IOException, ClassNotFoundException {Person p = new Person (); p.setAge (20); p.setName ("Joe"); Adres a = nieuw adres (); a.setHouseNumber (1); Medewerker e = nieuwe medewerker (); e.setPerson (p); e.setAddress (a); FileOutputStream fileOutputStream = nieuwe FileOutputStream ("yourfile2.txt"); ObjectOutputStream objectOutputStream = nieuwe ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (e); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = nieuwe FileInputStream ("yourfile2.txt"); ObjectInputStream objectInputStream = nieuwe ObjectInputStream (fileInputStream); Werknemer e2 = (Werknemer) objectInputStream.readObject (); objectInputStream.close (); assertTrue (e2.getPerson (). getAge () == e.getPerson (). getAge ()); assertTrue (e2.getAddress (). getHouseNumber () == e.getAddress (). getHouseNumber ()); }

In deze code zien we hoe we enkele niet-serialiseerbare attributen kunnen opslaan door serialisering Adres met aangepaste serialisering. Merk op dat we de niet-serialiseerbare attributen moeten markeren als voorbijgaand om de NotSerializableException.

4. Conclusie

In deze korte zelfstudie hebben we Java-serialisering besproken, belangrijke dingen besproken waarmee u rekening moet houden en hebben we laten zien hoe u aangepaste serialisering kunt uitvoeren.

Zoals altijd is de broncode die in deze tutorial wordt gebruikt, beschikbaar op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found