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 序列化的主要内容,如果未能解决你的问题,请参考以下文章