Introduktion til Java Serialization

1. Introduktion

Serialisering er konvertering af et objekts tilstand til en byte-strøm; deserialisering gør det modsatte. Sagt på en anden måde er serialisering konvertering af et Java-objekt til en statisk strøm (sekvens) af bytes, som derefter kan gemmes i en database eller overføres over et netværk.

2. Serialisering og deserialisering

Serialiseringsprocessen er instansuafhængig, dvs. objekter kan serieiseres på en platform og deserialiseres på en anden. Klasser, der er kvalificerede til serialisering, skal implementere en speciel markørgrænsefladeSerialiserbar.

Begge ObjectInputStream og ObjectOutputStream er klasser på højt niveau, der strækker sig java.io.InputStream og java.io.OutputStream henholdsvis. ObjectOutputStream kan skrive primitive typer og grafer af objekter til en OutputStream som en strøm af bytes. Disse streams kan efterfølgende læses ved hjælp af ObjectInputStream.

Den vigtigste metode i ObjectOutputStream er:

offentlig endelig ugyldig writeObject (Objekt o) kaster IOException;

Hvilket tager et objekt, der kan serialiseres, og konverterer det til en sekvens (stream) af bytes. Tilsvarende er den vigtigste metode i ObjectInputStream er:

offentlig endelig Objekt readObject () kaster IOException, ClassNotFoundException;

Hvilket kan læse en strøm af bytes og konvertere den tilbage til et Java-objekt. Dette kan derefter kastes tilbage til det originale objekt.

Lad os illustrere serialisering med en Person klasse. Noter det statiske felter tilhører en klasse (i modsætning til et objekt) og er ikke seriel. Bemærk også, at vi kan bruge nøgleordet forbigående at ignorere klassefelter under serialisering:

offentlig klasse Person implementerer Serialiserbar {privat statisk endelig lang serialVersionUID = 1L; statisk strengland = "ITALIEN"; privat int alder privat strengnavn; forbigående int-højde; // getters og setters}

Testen nedenfor viser et eksempel på at gemme et objekt af typen Person til en lokal fil, læs derefter denne værdi tilbage i:

@Test offentlig ugyldig nårSerializingAndDeserializing_ThenObjectIsTheSame () () kaster IOException, ClassNotFoundException {Person person = ny person (); person.setAge (20); person.setName ("Joe"); FileOutputStream fileOutputStream = ny FileOutputStream ("dinfil.txt"); ObjectOutputStream objectOutputStream = ny ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (person); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = ny FileInputStream ("dinfil.txt"); ObjectInputStream objectInputStream = ny ObjectInputStream (fileInputStream); Person p2 = (Person) objectInputStream.readObject (); objectInputStream.close (); assertTrue (p2.getAge () == p.getAge ()); assertTrue (p2.getName (). er lig med (p.getName ())); }

Vi brugte ObjectOutputStream for at gemme tilstanden for dette objekt i en fil ved hjælp af FileOutputStream. Filen “Dinfil.txt” oprettes i projektmappen. Denne fil indlæses derefter ved hjælp af FileInputStream.ObjectInputStream plukker denne strøm op og konverterer den til et nyt objekt kaldet p2.

Endelig tester vi tilstanden for det indlæste objekt, og det matcher det oprindelige objekts tilstand.

Bemærk, at det indlæste objekt skal udtrykkeligt kastes til en Person type.

3. Java Serialization forbehold

Der er nogle advarsler, der vedrører serialisering i Java.

3.1. Arv og sammensætning

Når en klasse implementerer java.io.Serialiserbar interface, alle dens underklasser kan også serienummeres. Tværtimod, når et objekt har en henvisning til et andet objekt, skal disse objekter implementere Serialiserbar interface separat, ellers a NotSerializableException vil blive kastet:

offentlig klasse Person implementerer Serialiserbar {privat int alder; privat strengnavn; privat adresse land; // skal også serienummeres} 

Hvis et af felterne i et serie, der kan serialiseres, består af en række objekter, skal alle disse objekter også kunne serienummeres, ellers skal NotSerializableException vil blive kastet.

3.2. Seriel version UID

JVM forbinder en version (lang) nummer med hver klasse, der kan serienummeres. Det bruges til at kontrollere, at de gemte og indlæste objekter har de samme attributter og dermed er kompatible ved serialisering.

Dette nummer kan genereres automatisk af de fleste IDE'er og er baseret på klassens navn, dets attributter og tilknyttede adgangsmodifikatorer. Enhver ændring resulterer i et andet nummer og kan forårsage et InvalidClassException.

Hvis en serie, der kan serialiseres, ikke erklærer en serialVersionUID, vil JVM generere en automatisk ved kørselstid. Det anbefales dog stærkt, at hver klasse erklærer sit serialVersionUID da den genererede er compilerafhængig og dermed kan resultere i uventet InvalidClassExceptions.

3.3. Tilpasset serialisering i Java

Java angiver en standard måde, hvorpå objekter kan serieiseres. Java-klasser kan tilsidesætte denne standardadfærd. Brugerdefineret serialisering kan være særligt nyttigt, når man prøver at serieisere et objekt, der har nogle ikke-serierbare attributter. Dette kan gøres ved at tilvejebringe to metoder inden for klassen, som vi vil serieisere:

privat ugyldigt writeObject (ObjectOutputStream ud) kaster IOException;

og

privat ugyldigt readObject (ObjectInputStream in) kaster IOException, ClassNotFoundException;

Med disse metoder kan vi serieisere disse ikke-serialiserbare attributter til andre former, der kan serieiseres:

offentlig klasse Medarbejder implementerer Serialiserbar {privat statisk endelig lang serialVersionUID = 1L; privat forbigående adresse adresse; privat person person; // setters og getters private ugyldige writeObject (ObjectOutputStream oos) kaster IOException {oos.defaultWriteObject (); oos.writeObject (address.getHouseNumber ()); } privat ugyldigt readObject (ObjectInputStream ois) kaster ClassNotFoundException, IOException {ois.defaultReadObject (); Heltal husNummer = (Heltal) ois.readObject (); Adresse a = ny adresse (); a.setHouseNumber (houseNumber); this.setAddress (a); }}
offentlig klasse Adresse {private int houseNumber; // settere og getters}

Følgende enhedstest tester denne brugerdefinerede serialisering:

@Test offentlig ugyldig nårCustomSerializingAndDeserializing_ThenObjectIsTheSame () kaster IOException, ClassNotFoundException {Person p = ny person (); p.setAge (20); p.setName ("Joe"); Adresse a = ny adresse (); a.setHouseNumber (1); Medarbejder e = ny medarbejder (); e.setPerson (p); e.setAddress (a); FileOutputStream fileOutputStream = ny FileOutputStream ("dinfil2.txt"); ObjectOutputStream objectOutputStream = ny ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (e); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = ny FileInputStream ("dinfil2.txt"); ObjectInputStream objectInputStream = ny ObjectInputStream (fileInputStream); Medarbejder e2 = (Medarbejder) objectInputStream.readObject (); objectInputStream.close (); assertTrue (e2.getPerson (). getAge () == e.getPerson (). getAge ()); assertTrue (e2.getAddress (). getHouseNumber () == e.getAddress (). getHouseNumber ()); }

I denne kode ser vi, hvordan man gemmer nogle ikke-seriable attributter ved at serialisere Adresse med tilpasset serialisering. Bemærk, at vi skal markere de userialiserbare attributter som forbigående for at undgå NotSerializableException.

4. Konklusion

I denne hurtige vejledning har vi gennemgået Java-serialisering, diskuteret vigtige ting at huske på og har vist, hvordan man laver tilpasset serialisering.

Som altid er kildekoden, der bruges i denne vejledning, tilgængelig på GitHub.