Serialization of Java basics

Hello, everyone! I am Laochou, an old and ugly forerunner! Today I’m going to talk about serialization.

So,

What is serialization?

Serialization is the process of converting the state information of an object (in memory) into a form that can be stored or transmitted. In plain English, an object is stored in some form on some medium.

Now that the object is stored in some form, how do you restore it?

There is a strategy called deserialization. Deserialization, as the name suggests, is the conversion of some form of storage to the original object.

Use of serialization

  • You need to store objects in memory on some medium.
  • You need to transfer objects in memory over the network.
  • RPC calls

How is serialization supported in Java

Serialization is supported in Java in two ways. I’ll tell you all about it.

Serializable

This interface, it stands alone. No other interfaces are inherited (interfaces can be inherited). And it doesn’t have any methods to implement.

public interface Serializable {
}
Copy the code

Therefore, the Serializable interface serves only as an identifier and can only be serialized if it is implemented, otherwise an exception will be thrown.

Serialization stores exactly what information (see definition is the state information of the object). So serialization does not serialize static member variables. Note the pitfalls.

Let’s define a Person class.

Public class Person implements Serializable {// Private String name; // private int age; // get and set method public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // The toString method must be overridden here, otherwise the printed object will be the address. @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }}Copy the code

Next, we serialize through a main class. (Code by name, so few comments)

import java.io.*; Public class Main {// user.dir this property is very important, you may use this property in future file uploads, we can get the current project path. private static final String prefix = System.getProperty("user.dir"); public static void main(String[] args) { Person person = new Person(); person.setName("laochou"); person.setAge(19); serialPerson(person); deserialPerson(); } public static void serialPerson(Person Person) {ObjectOutputStream ObjectOutputStream = null; FileOutputStream fileOutputStream = null; try { File file = new File(prefix+ "\\" + "person.txt"); // Check if file exists if(! file.exists()) { boolean result = file.createNewFile(); If (result) {system.out.println (" file created successfully "); }else {system.out.println (" file creation failed, serialization aborted prematurely "); return; } } fileOutputStream = new FileOutputStream(file); objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(person); } catch (IOException e) { e.printStackTrace(); }finally {// Remember that resources must be opened and then closed, and then opened and then closed. Try {if(objectOutputStream! = null) { objectOutputStream.close(); } if(fileOutputStream ! = null) { fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); Public static void deserialPerson() {ObjectInputStream ObjectInputStream = null; FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(prefix + "\\" + "person.txt"); objectInputStream = new ObjectInputStream(fileInputStream); Person person = (Person) objectInputStream.readObject(); System.out.println(person); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }finally {// Remember that resources must be opened and then closed, and then opened and then closed. Try {if(objectInputStream! = null) { objectInputStream.close(); } if(fileInputStream ! = null) { fileInputStream.close(); } } catch (IOException e) { e.printStackTrace(); }}}}Copy the code

After running, screenshot of the effect.You can see that the program creates a person.txt file in the root directory of the project. Of course, if you open person.txt, you’ll find that you can’t read it (neither can I). And then we read it through the program.

At this point, your first serialization and deserialization programs are OK. Congratulations!! But is it really that simple?

serialVersionUID

Now, there’s a question about the Person class, what happens if I add a property, but I deserialize it using the same file that I already serialized. Look down

New stats, don’t lie to me.

The main method is commented out, leaving only the deserialization method.

public static void main(String[] args) {
//        Person person = new Person();
//        person.setName("laochou");
//        person.setAge(19);
//        serialPerson(person);
        deserialPerson();
}
Copy the code

And when you run the program, you’ll see. Oh my god! There’s a big problem. So let’s look at this problem

java.io.InvalidClassException: cn.laochou.pojo.Person; local class incompatible: stream classdesc serialVersionUID = 1841332452983081360, local class serialVersionUID = 8171920675667862597 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)  at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459) at Main.deserialPerson(Main.java:60) at Main.main(Main.java:15)Copy the code

Don’t panic when you encounter problems. Well, there’s a problem, so let’s solve it. An enemy will be blocked.

The local class is not compatible. What is the measure of compatibility. Read on. The serialVersionUID of the class in the stream (that is, the one we serialized and stored) is 1841332452983081360, whereas the serialVersionUID of our local class is 8171920675667862597. Normal people can find the two serialVersionUID is different, of course, if you want to say the same, then I will punch you.

Okay, they check compatibility by serialVersionUID.

So how to solve the above error ?????

The serialVersionUID attribute is not in our class. How did it come from? If we delete this property or set the default value, then it will be compatible.

That’s right, we’re trying to achieve compatibility by setting the same defaults. Okay, so we’re just going to be reluctant to set it, or it’s going to get an error. (Note here that we need to delete the No attribute of the Person class, add the serialVersionUID attribute, reserialize the file, add the NO attribute, and then just deserialize.)

Public class Person implements Serializable {// Add private static final Long serialVersionUID = 1; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }}Copy the code

Reserialization and deserialization to see if there is a problem.

public static void main(String[] args) {
      Person person = new Person();
      person.setName("laochou");
      person.setAge(19);
      serialPerson(person);
      deserialPerson();
}
Copy the code

With that done, we can add a new no attribute, add the get and set methods, and override the toString method.

public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; // Add attribute, we did not have no attribute in the previous serialization process. People have to figure this out. private int no; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", no=" + no + '}'; }}Copy the code

Deserialize.

public static void main(String[] args) {
//        Person person = new Person();
//        person.setName("laochou");
//        person.setAge(19);
//        serialPerson(person);
      deserialPerson();
}
Copy the code

Amazingly, there are no errors. I told you to get it wrong, and now Laochou is gonna kill you. Results the followingAs you can see, the new property is given a default value. The base type is different from the reference type, which is null. You can read it if you don’t know the basic typesWhat are the basic types in JAVA?

That someone say again, you this new attribute OK, then you now delete an original attribute will how??

This is to

public class Person implements Serializable { private static final long serialVersionUID = 1L; // We serialized two attributes, one name and one age. Now it's a private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; }}Copy the code

After running, no error is reported, only one object is printed. Wouldn’t that be nice? Results the following

Okay, you should now know the importance of the serialVersionUID. It is critical for serialization and anti-sequence robustness. If we do not set the value of serialVersionUID by default, the program will generate one based on the class name, interface name, member variable, member method, and so on. From this, you can imagine that new attributes and deleted attributes, generated conditions change, generated values naturally change, so it is not surprising to report an error.

How many important things to say?? SerialVersionUID is important, important, important.

In the end is IDE does not speak wushu, or their practice is not in place?

SerialVersionUID is so important that the IDE doesn’t remind me, making it a headache to maintain (change code) later. I wanted to say, “Young man, I advise you rattail juice.” All right, are you sure this is it? Not much knowledge

“More!!” was all Laochou could say. .

transient

This keyword is also very important. (I won’t write the specific case, but try it myself.)

Now there is a scenario where some information in an object cannot be serialized due to confidentiality agreements. Once serialized, deserialization is a telltale.

At this point, we can use the transient keyword, we can use this keyword to modify our member variables, so during serialization, ignore.

Then some people ask, do use transient must not serialize??

The answer was: No! A transient is used and may be serialized.

Laochou lied to me. It said it was ignored and serialized. I’ll give you an example of JDK source code. Well, you don’t believe me. Don’t you believe the JDK source code? The elementData array member variables of ArrayList are transients, but ArrayList supports serialization, which is an extension point. ArrayList overrides the writeObject and readObject methods. If you can illustrate transient with this source code example, I’m sure the interviewer will be impressed.

If the interviewer asks you about serialization, you should be Serializable. The mouse tail juice

Externalizable

Externalizable is also an interface. Inherits the Serializable interface.

public interface Externalizable extends java.io.Serializable {
    void writeExternal(ObjectOutput out) throws IOException;
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
Copy the code

Notice that the Externalizable interface has two methods to implement. Therefore, to achieve serialization in this way, two methods must be implemented.

public class Animal implements Externalizable { private String name; private int age; Override public void writeExternal(ObjectOutput out) throws IOException {Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeObject(age); } @override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); age = (int) in.readObject(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Animal{" + "name='" + name + '\'' + ", age=" + age + '}'; }}Copy the code

Note that our property will be serialized even if we use the transient modifier but specify serialization in the writeExternal method. You can give it a try. (The specific serialization method and deserialization method flow remains unchanged, parameters need to be changed)

public static void serialAnimal(Animal animal) { ObjectOutputStream objectOutputStream = null; FileOutputStream fileOutputStream = null; try { File file = new File(prefix+ "\\" + "animal.txt"); if(! file.exists()) { boolean result = file.createNewFile(); If (result) {system.out.println (" file created successfully "); }else {system.out.println (" file creation failed, serialization aborted prematurely "); return; } } fileOutputStream = new FileOutputStream(file); objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(animal); } catch (IOException e) { e.printStackTrace(); }finally {// Remember that resources must be opened and then closed, and then opened and then closed. Try {if(objectOutputStream! = null) { objectOutputStream.close(); } if(fileOutputStream ! = null) { fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static void deserialAnimal() { ObjectInputStream objectInputStream = null; FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream(prefix + "\\" + "animal.txt"); objectInputStream = new ObjectInputStream(fileInputStream); Animal animal = (Animal) objectInputStream.readObject(); System.out.println(animal); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }finally {// Remember that resources must be opened and then closed, and then opened and then closed. Try {if(objectInputStream! = null) { objectInputStream.close(); } if(fileInputStream ! = null) { fileInputStream.close(); } } catch (IOException e) { e.printStackTrace(); }}}Copy the code

Very, very important details: The Externalizable interface to deserialize must use the no-argument constructor and must be public. There is no such requirement for Serializable, and Serializable also requires a constructor with no arguments, but there is no requirement for public modification. To verify this, we can write a no-argument constructor and change public to private. so

public class Animal implements Externalizable { private transient String name; private int age; @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeObject(age); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); age = (int) in.readObject(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Animal{" + "name='" + name + '\'' + ", age=" + age + '}'; } // Add this method to verify. private Animal() { } }Copy the code

Results the following

A lot of people say, why do we have to use a no-parameter constructor?

Because of the deserialization using Externalizable, when an object is read, the no-argument constructor of the serialized class is called to create a new object; The values of the fields of the saved object are then filled into the new object. This is why the no-argument constructor is called during deserialization. For this reason, a class implementing the Externalizable interface must provide a constructor with no arguments and its access is public.

At the bottom of Serializable is the ability to create objects through reflection. Read the source code or refer to relevant materials.

How to read the serialized TXT file

Sublime, an editor that can read directly in hexadecimal, is recommended.

With the change editor open only the following things, the following are hexadecimal Olympiad

aced 0005 7372 0016 636e 2e6c 616f 6368
6f75 2e70 6f6a 6f2e 5065 7273 6f6e 0000
0000 0000 0001 0200 0249 0003 6167 654c
0004 6e61 6d65 7400 124c 6a61 7661 2f6c
616e 672f 5374 7269 6e67 3b78 7000 0000
1374 0007 6c61 6f63 686f 75
Copy the code

Cafebabe 0005: indicates that the stream version 737:73 is an object, and after 72 is a description of our class. 0016: The length of the class name is 22 because it is hexadecimal. That’s 11 groups. 636E 2E6C 616F 6368 6F75 2E70 6F6A 6F2E 5065 7273 6F6E: indicates the class name. You’re not going to believe this, but I’m going to use Python to help you verify this and this is a Python validation command, so you can try it yourself.

[chr(int(i,16)) for i in "0x63 0x6e 0x2e 0x6c 0x61 0x6f 0x63 0x68 0x6f 0x75 0x2e 0x70 0x6f 0x6a 0x6f 0x2e 0x50 0x65 0x72  0x73 0x6f 0x6e".split()]Copy the code

That’s cn. Laochou.pojo. Person

Behind I will not translate, we want to explore, you can baidu or read a book to find information.

Details are doomed to success or failure, understand all understand, don’t live up to my special translation of a wave of hard.

Please answer

Thank you very much for your support. Because it’s not easy to see here.

We all work so hard anyway, so just work hard and answer some questions. Review for you

  • There are several ways that serialization is supported in Java. What are they?
  • What attributes should I pay attention to when using Serializable? (UID is not, say how many times)
  • If an attribute does not need to be serialized, what keyword should be used to modify it? Should this keyword not be serialized?
  • Which two methods need to be overridden when using Externalizable to support serialization. None of the constructors will report an error?
  • Question to consider: Do you consider XML and JSON formats as serialization?

You can exchange these questions in our QQ group. Ac group (additive group without losing conjunction)

Some of the words

This post is not just about serialization, but also a lot of thought and some extended points. Hope friends can get some knowledge.

Because dry goods must have code, I hope small partners can overcome.

Code word is not easy, feel good writing, welcome to like, attention, forwarding support. We want to share, but we need you to spark our plains.

Your support is the biggest motivation for our creation.

I am Laochou, an old and ugly forerunner! See you next time.

Previous recommendations:

  • Did you get offers from Alibaba and Tencent when you were an undergraduate?
  • What did you experience when you got 30W annual salary as an undergraduate?
  • Only fast graduation ability has obtain employment pressure?
  • BAT f * * king internship fun?
  • Java basic String