现在的位置: 首页 > 综合 > 正文

Java学习札记9:Understand The SerialVersionUID

2018年04月04日 ⁄ 综合 ⁄ 共 4789字 ⁄ 字号 评论关闭

If you ever implemented Serializable interface, you must encounter this warning message

The serializable class xxx does not declare a static final serialVersionUID field of type long


So…What Is SerialVersionUID?

The serialVersionUID is used as a version control in a Serializable class. If you do not explicitly declare a serialVersionUID, JVM will did it for you automatically, based on various aspects of
your Serializable class, as describe in the
Java(TM) Object Serialization Specification
.



SerialVersionUID Example

The above statement is a bit hard to understand at the beginning (as least i did), let start an example to understand how Serializable class use SerialVersionUID to implement version control.


1. Address.Java

A serializable class with a serialVersionUID of 1L.

import java.io.Serializable;
 
public class Address implements Serializable {
 
	   private static final long serialVersionUID = 1L;
 
	   String street;
	   String country;
 
	   public void setStreet(String street) {
		   this.street = street;
	   }
 
	   public void setCountry(String country) {
		   this.country = country;
	   }
 
	   public String getStreet() {
		   return this.street;
	   }
 
	   public String getCountry() {
		   return this.country;
	   }
 
	   @Override
	   public String toString() {
		return new StringBuffer(" Street : ")
			.append(this.street)
			.append(" Country : ")
			.append(this.country).toString();
	   }
}


2. WriteObject.Java

A simple class to write / serialize the Address object into a file – “c:\\address.ser”.

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
 
public class WriteObject {
 
	public static void main (String args[]) {

		Address address = new Address();
		address.setStreet("wall street");
		address.setCountry("united state");

		try {
			FileOutputStream fout = new FileOutputStream("c:\\address.ser");
			ObjectOutputStream oos = new ObjectOutputStream(fout);
			oos.writeObject(address);
			oos.close();
			System.out.println("Done");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}


3. ReadObject.Java

A simple class to read / deserialize the Address object from file – “c:\\address.ser”

import java.io.FileInputStream;
import java.io.ObjectInputStream;
 
public class ReadObject {

	public static void main (String args[]) {

		Address address;

		try {
			FileInputStream fin = new FileInputStream("c:\\address.ser");
			ObjectInputStream ois = new ObjectInputStream(fin);
			address = (Address) ois.readObject();
			ois.close();
		
			System.out.println(address);
		} catch (Exception ex) {
			ex.printStackTrace(); 
		}
	}
}



Testing

Let do some testing to demonstrate the use of serialVersionUID.


1. Same SerialVersionUID

Same serialVersionUID , there are no problem during deserialization process

javac Address.java
javac WriteObject.java
javac ReadObject.java
java WriteObject
java ReadObject
Street : wall street Country : united state


2. Different SerialVersionUID

In Address.java, change the serialVersionUID to 2L (it was 1L), and compile it again.

javac Address.java
java ReadObject
java.io.InvalidClassException: Address; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
        ... 
        at ReadObject.main(ReadObject.java:14)

The “InvalidClassException” will raise, because you write a serialization class with serialVersionUID “1L” but try to retrieve it back with updated serialization class, serialVersionUID “2L”.


The serialVersionUID have to match during the serialization and deserialization process.



When Should Update Your SerialVersionUID?

When your serialization class is updated by some incompatible Java type changes to a serializable class, you have to update your serialVersionUID.

For detail about the compatible and incompatible Java type changes to a serializable class, see theJava Object Serialization Specification.



What’s Wrong With The Default SerialVersionUID?

If no serialVersionUID is declare, JVM will used its own algorithm to generate a default SerialVersionUID, you can check the algorithmhere.

The default serialVersionUID computation is highly sensitive to class details and may vary from different JVM implementation, and result in an
unexpected InvalidClassExceptions during deserialization process.


1. Client / Server Environment

    - Client is using SUN’s JVM in Windows.

    - Server is using JRockit in Linux.


Client sends a serializable class with default generated serialVersionUID (e.g 123L) to server over socket, server may generate a different serialVersionUID (e.g 124L) during deserialization process,
and raise an unexpected InvalidClassExceptions.


2. File / Database Environment

    - App #1 is using SUN’s JVM in Windows.

    - App #2 is using JRockit in Linux.


Serialization is allow to save into a file or database. App #1 stores a serializable class into database with default generated serialVersionUID (e.g 123L), while App #2 may generate a different
serialVersionUID (e.g 124L) during deserialization process, and raise an unexpected InvalidClassExceptions.


You can check here for theList of the JVM implementation.



How To Generate SerialVersionUID

You can use JDK “serialver” or Eclipse IDE to generate serialVersionUID automatically, seedetail.



Conclusion

SUN is highly recommends developers to declare the serialVersionUID in order to avoid the different JVM issue listed above, however I rather recommend you should understand what is serialization,
how serialVersionUID implement version control and why your class need to use serialization. Understand the serialVersionUID concept is better than blindfold to any recommendation.






转载自:

http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/








抱歉!评论已关闭.