Introduksjon til Java Serialization

1. Introduksjon

Serialisering er konvertering av tilstanden til et objekt til en byte-strøm; deserialisering gjør det motsatte. Sagt på en annen måte er serialisering konvertering av et Java-objekt til en statisk strøm (sekvens) av byte som deretter kan lagres i en database eller overføres over et nettverk.

2. Serialisering og deserialisering

Serialiseringsprosessen er forekomstuavhengig, dvs. objekter kan serieiseres på en plattform og deserialiseres på en annen. Klasser som er kvalifisert for serialisering, må implementere et spesielt markørgrensesnittSerialiserbar.

Både ObjectInputStream og ObjectOutputStream er klasser på høyt nivå som strekker seg java.io.InputStream og java.io.OutputStream henholdsvis. ObjectOutputStream kan skrive primitive typer og grafer av objekter til en OutputStream som en strøm av byte. Disse strømmer kan deretter leses ved hjelp av ObjectInputStream.

Den viktigste metoden i ObjectOutputStream er:

offentlig endelig ugyldig writeObject (Object o) kaster IOException;

Som tar et objekt som kan serialiseres, og konverterer det til en sekvens (strøm) av byte. Tilsvarende er den viktigste metoden i ObjectInputStream er:

offentlig endelig Objekt readObject () kaster IOException, ClassNotFoundException;

Som kan lese en strøm av byte og konvertere den tilbake til et Java-objekt. Dette kan deretter kastes tilbake til det opprinnelige objektet.

La oss illustrere serialisering med en Person klasse. Noter det statiske felt tilhører en klasse (i motsetning til et objekt) og er ikke seriell. Vær også oppmerksom på at vi kan bruke nøkkelordet flyktig for å ignorere klassefelt under serialisering:

offentlig klasse Personredskaper Serialiserbar {privat statisk endelig lang serialVersionUID = 1L; statisk strengland = "ITALIA"; privat alder; privat strengnavn; forbigående int høyde; // getters og setters}

Testen nedenfor viser et eksempel på lagring av et objekt Person til en lokal fil, og les deretter denne verdien tilbake i:

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

Vi brukte ObjectOutputStream for å lagre tilstanden til dette objektet i en fil ved hjelp av FileOutputStream. Filen “Yourfile.txt” blir opprettet i prosjektkatalogen. Denne filen lastes deretter inn med FileInputStream.ObjectInputStream plukker opp denne strømmen og konverterer den til et nytt objekt som heter p2.

Til slutt tester vi tilstanden til det lastede objektet, og det samsvarer med tilstanden til det opprinnelige objektet.

Legg merke til at det lastede objektet eksplisitt må kastes til en Person type.

3. Advarsler om Java-serialisering

Det er noen advarsler som gjelder serialisering i Java.

3.1. Arv og sammensetning

Når en klasse implementerer java.io Serialiserbar grensesnitt, alle underklasser kan også serienummeres. Tvert imot, når et objekt har en referanse til et annet objekt, må disse objektene implementere Serialiserbar grensesnitt separat, ellers a NotSerializableException vil bli kastet:

offentlig klasse Personredskaper Serialiserbar {privat int alder; privat strengnavn; privat adresse land; // må også serienummeres} 

Hvis et av feltene i et objekt som kan serialiseres, består av en rekke objekter, må alle disse objektene også kunne serienummeres, ellers NotSerializableException vil bli kastet.

3.2. Seriell versjon UID

JVM knytter en versjon (lang) nummer med hver serie som kan serienummeres. Den brukes til å verifisere at de lagrede og lastede objektene har samme attributter og dermed er kompatible ved serialisering.

Dette nummeret kan genereres automatisk av de fleste IDEer og er basert på klassens navn, dets attributter og tilknyttede tilgangsmodifikatorer. Eventuelle endringer resulterer i et annet tall og kan forårsake et InvalidClassException.

Hvis en serie som ikke kan klassifiseres, ikke erklærer en serialVersionUID, vil JVM generere en automatisk ved kjøretid. Det anbefales imidlertid på det sterkeste at hver klasse erklærer sin serialVersionUID ettersom den genererte er avhengig av kompilatoren og dermed kan føre til uventet InvalidClassExceptions.

3.3. Egendefinert serialisering i Java

Java angir en standard måte som objekter kan serieiseres på. Java-klasser kan overstyre denne standardadferden. Tilpasset serialisering kan være spesielt nyttig når du prøver å serieisere et objekt som har noen ikke-serierbare attributter. Dette kan gjøres ved å tilby to metoder i klassen som vi ønsker å serieisere:

privat ugyldig writeObject (ObjectOutputStream ut) kaster IOException;

og

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

Med disse metodene kan vi serieisere disse userialiserbare attributtene til andre former som kan serialiseres:

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

Følgende enhetstest tester denne tilpassede serielliseringen:

@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); Ansatt e = ny ansatt (); e.setPerson (p); e.setAddress (a); FileOutputStream fileOutputStream = ny FileOutputStream ("yourfile2.txt"); ObjectOutputStream objectOutputStream = ny ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (e); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = ny FileInputStream ("yourfile2.txt"); ObjectInputStream objectInputStream = ny ObjectInputStream (fileInputStream); Ansatt e2 = (Ansatt) objectInputStream.readObject (); objectInputStream.close (); assertTrue (e2.getPerson (). getAge () == e.getPerson (). getAge ()); assertTrue (e2.getAddress (). getHouseNumber () == e.getAddress (). getHouseNumber ()); }

I denne koden ser vi hvordan du lagrer noen ikke-serierbare attributter ved å serialisere Adresse med tilpasset serialisering. Vær oppmerksom på at vi må merke de userialiserbare attributtene som flyktig for å unngå NotSerializableException.

4. Konklusjon

I denne raske opplæringen har vi gjennomgått Java-serialisering, diskutert viktige ting å huske på og har vist hvordan du gjør tilpasset serialisering.

Som alltid er kildekoden som brukes i denne opplæringen, tilgjengelig på GitHub.