Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the problems with Java serialization

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "what are the problems with Java serialization", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn what are the problems with Java serialization.

Question 1: what is Java serialization?

Serialization is the process of changing an object to a binary format that can be saved to disk or sent over the network to other running Java virtual machines, and the object state can be restored by deserialization. Java serialization API provides developers with a standard mechanism: by implementing java.io.Serializable or java.io.Externalizable interfaces, ObjectInputStream and ObjectOutputStream handle object serialization. When implementing the java.io.Externalizable interface, Java programmers are free to choose either the standard serialization based on the class structure or their custom binary format, which is generally considered the best practice, because the serialized binary format becomes part of the class output API and may break the encapsulation of private and package-visible attributes in Java.

What on earth is the use of serialization?

Implement java.io.Serializable.

Define user classes:

Class User implements Serializable {private String username; private String passwd; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd;} public void setPasswd (String passwd) {this.passwd = passwd;}}

We serialize the object, store it in the txt file through ObjectOutputStream, read the txt file through ObjectInputStream, and deserialize it into a User object.

Public class TestSerialize {public static void main (String [] args) {User user = new User (); user.setUsername ("hengheng"); user.setPasswd ("123456"); System.out.println ("read before Serializable:"); System.out.println ("username:" + user.getUsername ()); System.err.println ("password:" + user.getPasswd ()) Try {ObjectOutputStream os = new ObjectOutputStream (new FileOutputStream ("/ Users/admin/Desktop/test/user.txt")); os.writeObject (user); / / write the User object to the file os.flush (); os.close ();} catch (FileNotFoundException e) {e.printStackTrace () } catch (IOException e) {e.printStackTrace ();} try {ObjectInputStream is = new ObjectInputStream (new FileInputStream ("/ Users/admin/Desktop/test/user.txt")); user = (User) is.readObject (); / / read User data is.close () from the stream System.out.println ("\ nread after Serializable:"); System.out.println ("username:" + user.getUsername ()); System.err.println ("password:" + user.getPasswd ());} catch (FileNotFoundException e) {e.printStackTrace ();} catch (IOException e) {e.printStackTrace () } catch (ClassNotFoundException e) {e.printStackTrace ();}

The running results are as follows:

Pre-serialization data: username: henghengpassword: 123456 Post-serialization data: username: henghengpassword: 123456

At this point, we probably know what serialization is.

Question 2: when serializing, you want some members not to serialize, how do you implement it?

Answer: declare the member static or transient and will not be serialized during Java serialization.

Static variable: add the static keyword.

Transient variable: add the transient keyword.

Let's first try to declare the variable as transient.

Class User implements Serializable {private String username; private transient String passwd; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd;} public void setPasswd (String passwd) {this.passwd = passwd;}

Add the transient keyword before the password field before running. Running result:

Pre-serialization data: username: henghengpassword: 123456 Post-serialization data: username: henghengpassword: null

Through the running results, it is found that the password has not been serialized, which achieves our goal.

Try adding the static keyword before the user name again.

Class User implements Serializable {private static String username; private transient String passwd; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd;} public void setPasswd (String passwd) {this.passwd = passwd;}

Running result:

Pre-serialization data: username: henghengpassword: 123456 Post-serialization data: username: henghengpassword: null

We found that the result after running is not the same as expected, and username should also be changed to null in theory. What causes it?

The reason is that the value of the static variable username in the deserialized class is the value of the corresponding static variable in the current JVM, not deserialized.

Let's prove it:

Public class TestSerialize {public static void main (String [] args) {User user = new User (); user.setUsername ("hengheng"); user.setPasswd ("123456"); System.out.println ("pre-serialization data:"); System.out.println ("username:" + user.getUsername ()); System.err.println ("password:" + user.getPasswd ()) Try {ObjectOutputStream os = new ObjectOutputStream (new FileOutputStream ("/ Users/admin/Desktop/test/user.txt")); os.writeObject (user); / / write the User object to the file os.flush (); os.close ();} catch (FileNotFoundException e) {e.printStackTrace () } catch (IOException e) {e.printStackTrace ();} User.username = "Xiaoming"; try {ObjectInputStream is = new ObjectInputStream (new FileInputStream ("/ Users/admin/Desktop/test/user.txt")); user = (User) is.readObject (); / / read User data from the stream is.close () System.out.println ("\ nserialized data:"); System.out.println ("username:" + user.getUsername ()); System.err.println ("password:" + user.getPasswd ());} catch (FileNotFoundException e) {e.printStackTrace ();} catch (IOException e) {e.printStackTrace () } catch (ClassNotFoundException e) {e.printStackTrace ();} class User implements Serializable {public static String username; private transient String passwd; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd } public void setPasswd (String passwd) {this.passwd = passwd;}}

Change the value of the static variable username to "Xiao Ming" before deserialization.

User.username = "Xiao Ming"

Run it again:

Pre-serialization data: username: henghengpassword: 123456 Post-serialization data: username: Xiaoming password: null

Sure enough, the username here is the value of the static variable in JVM, not the deserialized value.

Question 3: what is the use of serialVersionUID?

We often customize a serialVersionUID in the class:

Private static final long serialVersionUID = 8294180014912103005L

What is the use of this serialVersionUID? What will happen if you don't set it up?

SerialVersionUID is a private static final long ID, and when it is printed on an object, it is usually the hash code of the object. SerialVersionUID can be defined or generated by itself.

The consequence of not specifying serialVersionUID is that when you add or modify any fields in a class, the serialized class will not be able to recover because the serialVersionUID generated by the new class and the old serialized object will be different. The process of Java serialization relies on the correct serialization object to recover the state and throws an java.io.InvalidClassException invalid class exception if the serialization object sequence version does not match.

For example, you will understand:

We leave the previously saved serialization file unchanged, and then modify the User class.

Class User implements Serializable {public static String username; private transient String passwd; private String age; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd;} public void setPasswd (String passwd) {this.passwd = passwd;} public String getAge () {return age } public void setAge (String age) {this.age = age;}}

Add an attribute age, and then write a separate deserialization method:

Public static void main (String [] args) {try {ObjectInputStream is = new ObjectInputStream (new FileInputStream ("/ Users/admin/Desktop/test/user.txt")); User user = (User) is.readObject (); / / read the data of User from the stream is.close (); System.out.println ("\ nmodify the data of User class:") System.out.println ("username:" + user.getUsername ()); System.err.println ("password:" + user.getPasswd ());} catch (FileNotFoundException e) {e.printStackTrace ();} catch (IOException e) {e.printStackTrace ();} catch (ClassNotFoundException e) {e.printStackTrace ();}}

An error was reported, and we found that the serialVersionUID generated by the previous User class was different from the modified serialVersionUID (because it was generated by the object's hash code), resulting in an InvalidClassException exception.

Custom serialVersionUID:

Class User implements Serializable {private static final long serialVersionUID = 4348344328769804325L; public static String username; private transient String passwd; private String age; public String getUsername () {return username;} public void setUsername (String username) {this.username = username;} public String getPasswd () {return passwd;} public void setPasswd (String passwd) {this.passwd = passwd } public String getAge () {return age;} public void setAge (String age) {this.age = age;}}

Try again:

Pre-serialization data: username: henghengpassword: 123456 Post-serialization data: username: Xiaoming password: null

No error is reported in the run result, so it is generally necessary to customize the serialVersionUID.

Question 4: can I customize the serialization process?

The answer is of course yes.

Earlier, we introduced the second way of serialization:

Implement the Externalizable interface, and then override the writeExternal () and readExternal () methods so that you can customize the serialization.

For example, we try to set the variable to transient.

Public class ExternalizableTest implements Externalizable {private transient String content = "I am a variable modified by transient"; @ Override public void writeExternal (ObjectOutput out) throws IOException {out.writeObject (content);} @ Override public void readExternal (ObjectInput in) throws IOException, ClassNotFoundException {content = (String) in.readObject ();} public static void main (String [] args) throws Exception {ExternalizableTest et = new ExternalizableTest () ObjectOutput out = new ObjectOutputStream (new FileOutputStream (new File ("test")); out.writeObject (et); ObjectInput in = new ObjectInputStream (new FileInputStream (new File ("test"); et = (ExternalizableTest) in.readObject (); System.out.println (et.content); out.close (); in.close ();}}

Running result:

I am a variable modified by transient.

The Externalizable interface is implemented here, so nothing can be serialized automatically, and you need to manually specify the variables to be serialized in the writeExternal method, regardless of whether it is decorated by transient or not.

At this point, I believe you have a deeper understanding of "what are the problems with Java serialization?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report