Java序列化

本文详细介绍了Java序列化的概念、实现方式及其应用场景。包括序列化的基本原理、实现步骤、哪些内容可以序列化,以及序列化过程中的难点总结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java序列化

序列化就是一种用来存储对象的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对象流进行读写操作时所引发的问题。序列化的目的还是存储和传输数据。

序列化的实现

1. 将需要被序列化的类实现Serializable接口,

2. 使用一个输出流(FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,

3. 使用ObjectOutputStream对象的writeObject(Object obj)方法可以将对象输出到文件后者其他地方,要恢复的话则用输入流。

 

哪些内容可以序列化

声明为statictransient类型的成员数据不能被序列化。static代表类的状态,transient代表对象的临时数据;

n 只有属性值才需要序列化,方法是公共代码,不需要序列化的。

没有实现序列化的成员属性是不能直接序列化的,它的状态会被设置为null

n 如果父对象实现了序列化接口,则子对象也可以被序列化。

n 如果子对象实现了序列化接口,父类没实现序列化接口时,序列化子类的过程没问题,但是反序列化过程是通过反射载入创建实例的,会调用父类的无参数构造参数,所以父类必须有一个无参数构造函数

 

自定义序列化

//下面的方法会在序列化的过程中被调用   

1.     private void writeObject(ObjectOutputStream out){  

2.         try {  

3.             out.defaultWriteObject(); //这个方法会把这当前中非静态变量和非transient变量写到流中                                        

4.         //下面的语句可以把任何序列化的对象的一些值放进去,尽管这个对象没有实现序列化接口,实际上是把这个对象的成员序列化进去了。

5.         out.writeInt(book.getIsbn());//ObjectOutputStream中提供了写基本类型数据的方法  

6.         //out.close();//注意,这句千万不能有,否刚将直接导致写入失败  

7.         } catch (IOException e) {  

8.             e.printStackTrace();  

9.         }   

10.     }  

11.       

12.     //这个方法会在反序列化的过程中被自动调用  

13.     private void readObject(ObjectInputStream in){  

14.         try {  

15.             in.defaultReadObject(); //和defaultWriteObject()方法相对应,默认的反序列化方法,会从流中读取   

16.             int isbn  = in.readInt(); //用这个方法来读取一个int型值

17.             book  = new Book(isbn); //这里我们就通过读取的保存的状态构造了一个和原来一样的Book对象  

18.             //in.close();同样的这句也不能有  

19.         } catch (IOException e) {  

20.             e.printStackTrace();  

21.         } catch (ClassNotFoundException e) {  

22.             e.printStackTrace();  

23.         }  

24.     }  

从自定义序列化的过程中也能看出,序列化在具体实施过程中是怎样的一个过程。

在向ObjectOutputStream中写入序列化对象,执行writeObject方法时,会首先执行序列化对象中的writeObject方法,如果没有这个方法,则执行流默认的写入方法,默认的写入方法只会写入非静态和非临时的对象。

如果序列化对象有writeObject方法,则在方法中先调用流对象的默认写入方法,然后可以自定义的再写入其他实现序列化接口的成员。从这个过程也能看出,只有成员变量才能够被写入,而方法是不能写入的。

 

序列化的难点总结

1,静态变量、临时变量、方法,都不会被序列化出去,而是直接赋值null

2,没有实现序列化接口的对象成员,可以添加writeObject方法,在方法中写入该对象成员的成员。

3,父类没有实现序列化,子类实现序列化,在序列化没问题,反序列化时需要父类必须有无参构造函数。

4,序列化ID,是序列化接口的一个成员,序列化唯一性的标识符。

 

 序列化ID的作用:  

序列化ID决定着是否能够成功反序列化!简单来说,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。等会我们可以通过代码验证一下。

序列化ID如何产生:

       当我们一个实体类中没有显示的定义一个名为“serialVersionUID”、类型为long的变量时,Java序列化机制会根据编译时的class自动生成一个serialVersionUID作为序列化版本比较,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID。譬如,当我们编写一个类时,随着时间的推移,我们因为需求改动,需要在本地类中添加其他的字段,这个时候再反序列化时便会出现serialVersionUID不一致,导致反序列化失败。那么如何解决呢?便是在本地类中添加一个“serialVersionUID”变量,值保持不变,便可以进行序列化和反序列化。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值