《Java编程思想》学习笔记9——对象序列化

Java的对象序列化是一个轻量级的持久化过程,序列化时,可以将java对象以字节序列形式写入硬盘、数据库或者通过网络传输到另一个JVM等等,反序列化是读取序列化的文件,将其在JVM中还原为java对象的过程。

1.简单的序列化和反序列化:

最简单的序列化是对象实现Serializable序列化接口,这个接口是一个标记接口,不需要实现任何方法。

下面的小例子简单展示java对象序列化和反序列化的过程:

[java]  view plain  copy
  1. import java.io.*;  
  2.   
  3. //简单的测试对象  
  4. public class TestObject implements Serializable{}  
  5.   
  6. import java.io.*;  
  7.   
  8. //序列化  
  9. public class SerializeObject{  
  10.     public static void main(String[] args)throws Exception{  
  11.         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“x.file”));  
  12.         TestObject obj = new TestObject();  
  13.         //将TestObject对象序列化到x.file文件中  
  14.         out.write(obj);  
  15. }  
  16. }  
  17.   
  18. import java.io.*;  
  19.   
  20. //反序列化  
  21. public class DeserializeObject{  
  22.     public static void main(String[] args)throw Exception{  
  23.         ObjectInputStream in = new ObjectInputStream(new FileInputStream(“x.file”));  
  24.         Object myObj = in.readObject();  
  25.         System.out.println(myObj.getClass());  
  26. }  
  27. }  

输出结果:

class TestObject

在序列化时,使用ObjectOutputStream将对象序列化写出,反序列化时,使用ObjectInputStream将对象反序列化读入。

注意:反序列化对象使用时,对象的class文件必须在classpath中,否则,JVM找不到对象的class文件会抛出ClassNotFoundException。

2.序列化控制:

默认的Serializable序列化是将对象整体序列化,但是对于一些特殊的需求例如:序列化部分对象或者反序列化部分对象的情况,就必须使用Externalizable接口来代替Serializable接口,Externalizable的writeExternal()和readExternal()方法可以实现对序列化的控制,这两个方法在对象序列化和反序列化时自动调用,例子如下:

[java]  view plain  copy
  1. import java.io.*;  
  2.   
  3. class Blip1 implements Externalizable{  
  4.     public Blip1(){  
  5.         System.out.println(“Blip1 Constructor”);  
  6. }  
  7. public void writeExternal(ObjectOutput out)throws IOException{  
  8.     System.out.println(“Blip1.writeExternal”);  
  9. }  
  10. public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{  
  11.     System.out.println(Blip1.readExternal);  
  12. }  
  13. }  
  14.   
  15. class Blip2 implements Externalizable{  
  16.     Blip1(){  
  17.         System.out.println(“Blip2 Constructor”);  
  18. }  
  19. public void writeExternal(ObjectOutput out)throws IOException{  
  20.     System.out.println(“Blip2.writeExternal”);  
  21. }  
  22. public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{  
  23.     System.out.println(Blip2.readExternal);  
  24. }  
  25. }  
  26.   
  27. public class Blips{  
  28.     public static void main(String[] args)throws IOException, ClassNotFoundException{  
  29.         System.out.println(“Constructing objects:”);  
  30.         Blip1 b1 = new Blip1();  
  31.         Blip2 b2 = new Blip2();  
  32.         //序列化  
  33.         ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Blips.out”));  
  34.         System.out.println(“Saving objects:”);  
  35.         o.writeObject(b1);  
  36.         o.writeObject(b2);  
  37.         //反序列化  
  38.         ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Blips.out”));  
  39.         System.out.println(“Recovering b1:”);  
  40.         b1 = (Blip1)in.readObject();  
  41.         //由于Blip2的默认无参数构造方法不是public的,所以会抛异常  
  42.         //System.out.println(“Recovering b2:”);  
  43.         //b2 = (Blip2)in.readObject();  
  44. }  
  45. }  

输出结果:

Constructing objects:

Blip1 Constructor

Blip2 Constructor

Saving objects:

Blip1.writeExternal

Blip2.writeExternal

Recovering b1:

Blip1 Constructor

Blip1.readExternal

注意:由于对象在反序列化时需要调用默认的public的无参数构造方法创建对象,所以Blip2非public类型无参数构造方法无法反序列化。所以使用Externalizable序列化和反序列化时,对象必须要有public类型的无参数构造方法,这一点是Externalizable和Serializable的区别。

Serializable和Externlizable反序列化的区别:

(1).Serializable的反序列化是通过序列化的字节数组序列进行反序列化的。对象的序列化的反序列化都是自动进行的。

(2).Externalizable的反序列化是通过调用默认的构造方法进行的。对象的序列化需要使用writeExternal()显式控制,对象的反序列化需要使用readExternal()显式控制,不是自动进行的。

3. Externlizable序列化高级:

使用Externlizable序列化和反序列化对象时,readExternal()和writeExternal()方法可以对象中指定字段进行初始化,例子如下:

[java]  view plain  copy
  1. import java.io.*;  
  2.   
  3. public class Test implements Externalizable{  
  4.     private int i;  
  5.     private String s;  
  6.     public Test(){  
  7.         System.out.println(“Test Constructor”);  
  8. }  
  9. public Test(String x, int a){  
  10.     System.out.println(“Test(String x, int a)”);  
  11.     i = a;  
  12.     s = x;  
  13. }  
  14. public void toString(){  
  15.     return s + i;  
  16. }  
  17. public void writeExternal(ObjectOutput out)throws IOException{  
  18.     System.out.println(“Test.writeExternal”);  
  19.     out.writeObject(s);  
  20.     out.writeInt(i);  
  21. }  
  22. public void readExternal(ObjectInput in)throws IOException, ClassNotFoundException{  
  23.     System.out.println(“Test.readExternal”);  
  24.     s = (String)in.readObject();  
  25.     i = in.readInt();  
  26. }  
  27. public static void main()throws IOException, ClassNotFoundException{  
  28.     System.out.println(“Constructing objects:”);  
  29.     Test t1 = new Test(“A String”, 47);  
  30.     Test t2 = new Test();  
  31.     System.out.println(t1);  
  32.     System.out.println(t2);  
  33.     //序列化  
  34.     ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Test.out”));  
  35.     System.out.println(“Saving objects:”);  
  36.     o.writeObject(t1);\  
  37.     o.writeObject(t2);  
  38.     o.close();  
  39.     //反序列化  
  40.     ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Test.out”));  
  41.     System.out.println(“Recovering objects:”);  
  42.     t1 = (Test)in.readObject();  
  43.     System.out.println(t1);  
  44.     t2 = (Test)in.readObject();  
  45.     System.out.println(t2);  
  46. }  
  47. }  

输出结果:

Constructing objects:

Test(String x, int a)

A String 47

Test Constructor

null0

Saving objects:

Test.writeExternal

Test.writeExternal

Recovering objects:

Test Constructor

Test.readExternal

A String 47

Test Constructor

Test.readExternal

null0

该例子中,当创建对象使用非无参数构造方法时,对象字段被初始化,因此序列化时可以将初始化的值保存。当创建对象使用无参数的构造方法时,对象的字段没有被赋值而使用默认的初始化值。反序列化时只会调用默认的无参数构造方法。

因此,为了使序列化和反序列化更高效使用,在序列化时,调用writeExternal()只写有用的重要数据,而在反序列化时,readObject()只读取有用的重要数据。

4.transient关键字:

当对象实现Serializable接口进行自动序列化时,类中某些字段不想被序列化,需要使用transient关键字,虽然Externalizable通过writeExternal()方法也可以实现此功能,但是序列化不是自动进行的,使用Serializable和transient关键字更加方便。

例子如下:


[java]  view plain  copy
  1. import java.io.*;  
  2.   
  3. public class User implements Serializable{  
  4.     private String username;  
  5.     private transient String password;  
  6.     public User(String name, String pwd){  
  7.         username = name;  
  8.         password = pwd;  
  9. }  
  10. public String toString(){  
  11.     return “username:” + username + “, password:” + password;  
  12. }  
  13. public static void main(String[] args)throws Exception{  
  14.     User user = new User(“Test”, “passwd”);  
  15.     System.out.println(“User=” + user);  
  16.     ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“User.out”));  
  17.     o.writeObject(user);  
  18.     o.close();  
  19.     ObjectInputStream in = new ObjectInputStream(new FileInputStream(“User.out”));  
  20.     System.out.println(“Recovering object:”);  
  21.     user = (User)in.readObject();  
  22.     System.out.println(“User=” + user);  
  23. }  
  24. }  

输出结果:

User=username:Test,password:passwd

Recovering object:

User=username:Test,password:null

注意:由于Externalizable默认序列化不存储任何字段,所以transient关键字只在Serializable中使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值