Java 序列化

Posted 胡子就不刮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 序列化相关的知识,希望对你有一定的参考价值。

 

Java序列化与反序列化是什么?

Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。

 

为什么需要序列化与反序列化?

当两个进程进行远程通信时,可以相互发送各种类型的数据,这些数据会以二进制序列的形式在网络上传送。

当两个Java进程进行通信时,能否实现进程间的对象传送?这就需要Java序列化与反序列化了。一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送,用的是序列化;另一方面,接收方需要从字节序列中恢复出Java对象,用的反序列化。

说白了一是为了数据持久化,二是为了让数据能够在不同平台互相传递。

 

如何实现Java序列化与反序列化?

只要实现了Serializable或Externalizable接口的类,对象就能实现序列化。

两者区别如下:

      1、Serializable序列化时不会调用默认的构造器,而Externalizable序列化时会调用默认构造器;


      2、Serializable:一个对象想要被序列化,那么它的类就要实现此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。

         Externalizable:它是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,实现这个接口,必须重写它的writeExternal()和readExternal()方法,然后在里面指定序列化哪些属性。

 

写到这来看看关键字 transient被它修饰的属性不会被序列化,由于Externalizable对象默认时不保存对象的任何字段,所以transient关键字只能伴随Serializable使用,虽然Externalizable对象中使用transient关键字也不报错,但不起任何作用。

 1 public class Person implements Serializable{
 2 
 3     private static final long serialVersionUID = -8492851170343220032L;
 4     private transient String name;//被关键字修饰过以后就不会被序列化
 5     private int age;//会被序列化
 6 
 7     public Person() {
 8     }
 9 
10     public String getName() {
11         return name;
12     }
13 
14     public void setName(String name) {
15         this.name = name;
16     }
17 
18     public int getAge() {
19         return age;
20     }
21 
22     public void setAge(int age) {
23         this.age = age;
24     }
25 
26 }

要想理解transient关键字更透彻的小伙伴可以自己百度,不会百度的程序员不是好的单身狗!

这里很多小伙伴写序列化的时候不喜欢写上序列号,也就是楼上代码的serialVersionUID,表示JVM会默认创建一个序列号,不需要自己实现,这边强调下,序列号必须写上!

序列化ID的作用  

       楼上序列化ID起着关键的作用,它决定着是否能够成功反序列化。java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。

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

  虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致。

 

文章结尾写一个序列化的例子:

Person实体类

 1 import java.io.Serializable;
 2 
 3 /**
 4  * Created by ht on 2017/7/31.
 5  */
 6 public class Person implements Serializable{
 7 
 8     private static final long serialVersionUID = -8492851170343220032L;
 9     private String name;
10     private int age;
11 
12     public Person() {
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public void setName(String name) {
20         this.name = name;
21     }
22 
23     public int getAge() {
24         return age;
25     }
26 
27     public void setAge(int age) {
28         this.age = age;
29     }

 

序列化实现类

 1 import java.io.*;
 2 
 3 /**
 4  * Created by ht on 2017/7/31.
 5  */
 6 public class SerializableTest implements Serializable{
 7 
 8     public static void main(String[] args) {
 9         Person person = new Person();
10         person.setAge(18);
11         person.setName("shuaige");
12         ObjectOutputStream out = null;
13         try{
14             out = new ObjectOutputStream(new FileOutputStream("C:/Users/ht/Desktop/Serializable.txt"));
15             out.writeObject(person);
16             System.out.println("序列化成功");
17         }catch (FileNotFoundException e){
18             e.printStackTrace();
19         }catch (IOException e){
20             e.printStackTrace();
21         }finally {
22                 try {
23                     out.close();
24                 } catch (IOException e) {
25                     e.printStackTrace();
26                 }
27         }
28     }
29 
30 }

执行输出:

序列化成功,同时相应路径上生成Serializable.txt文件,里面是一串字节序列

 

反序列化实现类

 1 import java.io.*;
 2 
 3 /**
 4  * Created by ht on 2017/7/31.
 5  */
 6 public class DesSerializeTest {
 7 
 8     public static void main(String[] args) {
 9             Person person = null;
10             ObjectInputStream in= null;
11             try {
12                 in = new ObjectInputStream(new FileInputStream("C:/Users/ht/Desktop/hello.txt"));
13                 try {
14                     person = (Person) in.readObject();
15                     System.out.println("反序列化成功");
16                     System.out.println(person.getName());
17                     System.out.println(person.getAge());
18                 } catch (ClassNotFoundException e) {
19                     e.printStackTrace();
20                 }
21             } catch (FileNotFoundException e) {
22                 e.printStackTrace();
23             } catch (IOException e) {
24                 e.printStackTrace();
25             } finally {
26                 try {
27                     in.close();
28                 } catch (IOException e) {
29                     e.printStackTrace();
30                 }
31             }
32         }
33     }

输出:

反序列化成功
shuaige
18

 




以上是关于Java 序列化的主要内容,如果未能解决你的问题,请参考以下文章

java 代码片段【JAVA】

# Java 常用代码片段

# Java 常用代码片段

创建片段而不从 java 代码实例化它

如何重构这个 Java 代码片段

java 反射代码片段