- 序列化:把java对象通过某种方式写入磁盘,或者传输给其他网络节点。即将对象转为二进制的过程。
- 反序列化:把磁盘中的文件,或者网络节点的数据通过某种方式转为java对象。即将二进制转为对象。
通过上面序列化的定义,可以初步了解序列化的使用场景。
- 将内存中的数据保存到磁盘或者数据库中。
- 需要在网络中传输对象。
- 想通过RMI传输对象。
下面直接上代码,通过代码实例学习如何实现序列化。
创建实体为了深入理解实现序列化与反序列化,首先创建几个实体。
User.java、Person.java、OtherInfo.java,他们的关系是User.java中引用了OtherInfo.java,User.java继承了Person.java。三个实体都有get/set/toString方法,方便查看测试效果。
为何创建创建这三个实体呢?
- 测试是否能序列化父类的数据
- 测试是否能序列化引用类型的数据
代码如下:
User.java
package org.ludk.serializable; import java.io.Serializable; public class User extends Person { private String name; private int age; private OtherInfo otherInfo; public User(String name, int age, OtherInfo otherInfo) { this.name = name; this.age = age; this.otherInfo = otherInfo; } @Override public String toString() { return "User{" + "name='" + name + ''' + ", age=" + age + ", otherInfo=" + otherInfo + '}'+ super.toString(); } 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 OtherInfo getOtherInfo() { return otherInfo; } public void setOtherInfo(OtherInfo otherInfo) { this.otherInfo = otherInfo; } }
OtherInfo.java
package org.ludk.serializable; import java.io.Serializable; public class OtherInfo { private String ph; private String address; public OtherInfo(String ph, String address) { this.ph = ph; this.address = address; } @Override public String toString() { return "OtherInfo{" + "ph='" + ph + ''' + ", address='" + address + ''' + '}'; } public String getPh() { return ph; } public void setPh(String ph) { this.ph = ph; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
Person.java
package org.ludk.serializable; import java.io.Serializable; public class Person { private String head; private String body; @Override public String toString() { return "Person{" + "head='" + head + ''' + ", body='" + body + ''' + '}'; } public String getHead() { return head; } public void setHead(String head) { this.head = head; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } }java序列化与反序列化工具类
SerializableUtil.java
package org.ludk.serializable; import java.io.*; public class SerializableUtil { public static void saveObject(Object object){ ObjectOutputStream objectOutputStream=null; FileOutputStream fileOutputStream=null; try { fileOutputStream=new FileOutputStream("D:\work\test\serializable\writeToFile.txt"); objectOutputStream=new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); objectOutputStream.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } public static Object readObject(){ ObjectInputStream objectInputStream=null; FileInputStream fileInputStream=null; try { fileInputStream=new FileInputStream("D:\work\test\serializable\writeToFile.txt"); objectInputStream=new ObjectInputStream(fileInputStream); return objectInputStream.readObject(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally { try { objectInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } }测试类
TestSerializable.java
package org.ludk.serializable; public class TestSerializable { public static void main(String[] args) { User user=new User("卢**",35,new OtherInfo("1834156****","北京海淀")); user.setHead("大头"); user.setBody("小身体"); //打印序列化前的对象 System.out.println(user); //序列化 SerializableUtil.saveObject(user); //反序列化 User readFromFile=(User) SerializableUtil.readObject(); //打印通过反序列化生成的对象 System.out.println(readFromFile); } }测试与修正的过程
- 运行TestSerializable.java的main方法,结果如下:
D:workjavabinjava.exe "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3libidea_rt.jar=51808:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3bin" -Dfile.encoding=UTF-8 -classpath D:workjavajrelibcharsets.jar;D:workjavajrelibdeploy.jar;D:workjavajrelibextaccess-bridge-64.jar;D:workjavajrelibextcldrdata.jar;D:workjavajrelibextdnsns.jar;D:workjavajrelibextjaccess.jar;D:workjavajrelibextjfxrt.jar;D:workjavajrelibextlocaledata.jar;D:workjavajrelibextnashorn.jar;D:workjavajrelibextsunec.jar;D:workjavajrelibextsunjce_provider.jar;D:workjavajrelibextsunmscapi.jar;D:workjavajrelibextsunpkcs11.jar;D:workjavajrelibextzipfs.jar;D:workjavajrelibjavaws.jar;D:workjavajrelibjce.jar;D:workjavajrelibjfr.jar;D:workjavajrelibjfxswt.jar;D:workjavajrelibjsse.jar;D:workjavajrelibmanagement-agent.jar;D:workjavajrelibplugin.jar;D:workjavajrelibresources.jar;D:workjavajrelibrt.jar;D:workspringcloud-demotargetclasses org.ludk.serializable.TestSerializable User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'} java.io.NotSerializableException: org.ludk.serializable.User at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17) java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.User at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422) at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18) Caused by: java.io.NotSerializableException: org.ludk.serializable.User at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17) null Process finished with exit code 0
java.io.NotSerializableException: org.ludk.serializable.User的意思很明显,org.ludk.serializable.User不能被实例化。
结论一:被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常
所以让org.ludk.serializable.User实现serializable接口,被调整的部分代码如下:
public class User extends Person implements Serializable {
- 再次跑测试类,结果如下:
D:workjavabinjava.exe "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3libidea_rt.jar=52041:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3bin" -Dfile.encoding=UTF-8 -classpath D:workjavajrelibcharsets.jar;D:workjavajrelibdeploy.jar;D:workjavajrelibextaccess-bridge-64.jar;D:workjavajrelibextcldrdata.jar;D:workjavajrelibextdnsns.jar;D:workjavajrelibextjaccess.jar;D:workjavajrelibextjfxrt.jar;D:workjavajrelibextlocaledata.jar;D:workjavajrelibextnashorn.jar;D:workjavajrelibextsunec.jar;D:workjavajrelibextsunjce_provider.jar;D:workjavajrelibextsunmscapi.jar;D:workjavajrelibextsunpkcs11.jar;D:workjavajrelibextzipfs.jar;D:workjavajrelibjavaws.jar;D:workjavajrelibjce.jar;D:workjavajrelibjfr.jar;D:workjavajrelibjfxswt.jar;D:workjavajrelibjsse.jar;D:workjavajrelibmanagement-agent.jar;D:workjavajrelibplugin.jar;D:workjavajrelibresources.jar;D:workjavajrelibrt.jar;D:workspringcloud-demotargetclasses org.ludk.serializable.TestSerializable User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'} java.io.NotSerializableException: org.ludk.serializable.OtherInfo at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17) java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.OtherInfo at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2341) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2265) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422) at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18) Caused by: java.io.NotSerializableException: org.ludk.serializable.OtherInfo at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27) at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17) null Process finished with exit code 0
java.io.NotSerializableException: org.ludk.serializable.OtherInfo
这段错误说明OtherInfo也要实现serializable接口。
结论二:引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常。
调整的部分代码如下:
public class OtherInfo implements Serializable{
- 再次跑测试类,结果如下:
D:workjavabinjava.exe "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3libidea_rt.jar=52382:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3bin" -Dfile.encoding=UTF-8 -classpath D:workjavajrelibcharsets.jar;D:workjavajrelibdeploy.jar;D:workjavajrelibextaccess-bridge-64.jar;D:workjavajrelibextcldrdata.jar;D:workjavajrelibextdnsns.jar;D:workjavajrelibextjaccess.jar;D:workjavajrelibextjfxrt.jar;D:workjavajrelibextlocaledata.jar;D:workjavajrelibextnashorn.jar;D:workjavajrelibextsunec.jar;D:workjavajrelibextsunjce_provider.jar;D:workjavajrelibextsunmscapi.jar;D:workjavajrelibextsunpkcs11.jar;D:workjavajrelibextzipfs.jar;D:workjavajrelibjavaws.jar;D:workjavajrelibjce.jar;D:workjavajrelibjfr.jar;D:workjavajrelibjfxswt.jar;D:workjavajrelibjsse.jar;D:workjavajrelibmanagement-agent.jar;D:workjavajrelibplugin.jar;D:workjavajrelibresources.jar;D:workjavajrelibrt.jar;D:workspringcloud-demotargetclasses org.ludk.serializable.TestSerializable User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'} User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='null', body='null'} Process finished with exit code 0
这次不抛异常了,但是父类Person.java的属性没有被序列化,head和body为空。
结论三:父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。
调整的部分代码如下:
public class Person implements Serializable{
- 再次跑测试类,结果如下:
D:workjavabinjava.exe "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3libidea_rt.jar=52500:C:Program FilesJetBrainsIntelliJ IDEA 2019.3.3bin" -Dfile.encoding=UTF-8 -classpath D:workjavajrelibcharsets.jar;D:workjavajrelibdeploy.jar;D:workjavajrelibextaccess-bridge-64.jar;D:workjavajrelibextcldrdata.jar;D:workjavajrelibextdnsns.jar;D:workjavajrelibextjaccess.jar;D:workjavajrelibextjfxrt.jar;D:workjavajrelibextlocaledata.jar;D:workjavajrelibextnashorn.jar;D:workjavajrelibextsunec.jar;D:workjavajrelibextsunjce_provider.jar;D:workjavajrelibextsunmscapi.jar;D:workjavajrelibextsunpkcs11.jar;D:workjavajrelibextzipfs.jar;D:workjavajrelibjavaws.jar;D:workjavajrelibjce.jar;D:workjavajrelibjfr.jar;D:workjavajrelibjfxswt.jar;D:workjavajrelibjsse.jar;D:workjavajrelibmanagement-agent.jar;D:workjavajrelibplugin.jar;D:workjavajrelibresources.jar;D:workjavajrelibrt.jar;D:workspringcloud-demotargetclasses org.ludk.serializable.TestSerializable User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'} User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'} Process finished with exit code 0
完美了。
听说静态变量不会被序列化( static,transient),我就不试了。
结论四:静态变量不会被序列化( static,transient)
序列化时一般会加入下面的代码(我没加):
private static final long serialVersionUID = 1L;
它决定着是否能够成功反序列化!
java的序列化机制是通过判断运行时类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
因为我测试的时候是用一个实体序列化和反序列化,所以看不出效果。
java序列化总结-
被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常。
-
引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常
-
父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。
-
静态变量不会被序列化( static,transient)
-
序列化ID应自己写,尽量不自动生成,因为序列化与反序列化的序列化ID应该保持一致