小言_互联网的博客

面试必备知识点—基础IO之 序列化与反序列化

483人阅读  评论(0)

1. 什么是序列化和反序列化

序列化: 把对象转换为字节序列的过程称为对象的序列化。

反序列化: 把字节序列恢复为对象的过程称为对象的反序列化。

有时候我们想把一些信息持久化保存起来,那么序列化的意思就是把内存里面的这些对象给变成一连串 的字节描述的过程。
常见的就是变成文件。但是问题来了,我就算不序列化,也可以保存到文件当中。 有什么问题吗

2. 什么时候需要序列化

1、把内存中的对象状态保存到一个文件中或者数据库中时候;

2、 用套接字在网络上传送对象的时候

3.实现序列化的方式

一定要牢记实现序列化本身是跟语言无关的

列举出一些其他实现序列化的方式(参考):

0、Java对象序列化
1、JSON序列化
2、XML
3、Protostuff
4、Hession(它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较 友好。)
5、Dubbo Serialization(阿里dubbo序列化)
6、FST(高性能、序列化速度大概是JDK的4-10倍,大小是JDK大小的1/3左右)
7、自定义协议进行序列化

4.如何实现序列化(Java对象序列化)

自己实现一个Person类,在类当中定义成员变量 name , age , sex , stuId , count ,如果要讲Person进行序列化需要实现Serializable接口即可 。

import java.io.Serializable
 class Person implements Serializable{   
  //private static final long serialVersionUID = 1L;    
  private String name;  
  private int age;  
  private String sex;  
  //transient修饰的变量,不能被序列化  
  transient private int stuId;  
  //static修饰的变量,不能被序列化  
   private static int count = 99;
    public String getName() {    
         return name;  
     }
    public int getAge() {     
         return age;  
     }
    public String getSex() {    
         return sex;  
     }
    public int getStuId() {     
         return stuId;  
     }
    public void setName(String name) {        
         this.name = name; 
      }
    public void setAge(int age) {     
         this.age = age;  
      }
    public void setSex(String sex) {    
        this.sex = sex;  
      }
    public void setStuId(int stuId) {        
    this.stuId = stuId;  
      }
       @Override  
   public String toString() {     
      return "Person{" +        
             "name='" + name + '\'' +                
             ", age=" + age +                
             ", sex='" + sex + '\'' +                     
             ", stuId=" + stuId +                
             ",count=" + count +         
                    '}';  
   } 
}

序列化反序列化测试:

public class TestDemo3 {  
  public static void main(String[] args) throws Exception {    
      serializePerson();     
      Person person = deserializePerson();        
      System.out.println(person.toString());  
        }   
         /**     * 序列化     */    
     private static void serializePerson() throws IOException {     
        Person person = new Person();        
        person.setName("agao");        
        person.setAge(10);        
        person.setSex("男");        
        person.setStuId(100);    
        // ObjectOutputStream 对象输出流,将 person 对象存储到E盘的    
       // person.txt 文件中,完成对 person 对象的序列化操作     
        ObjectOutputStream oos = new ObjectOutputStream                (new FileOutputStream(new File("e:/person.txt")));        
        oos.writeObject(person);        
        System.out.println("person 对象序列化成功!");        
        oos.close();  
          }
    /**     * 反序列化     */  
     private static Person deserializePerson() throws Exception {     
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("e:/person.txt")));   
        Person person = (Person) ois.readObject();        
        System.out.println("person 对象反序列化成功!");     
           return person;  
     } 
}

相关流的说明:

ObjectOutputStream 代表对象输出流: 它的 writeObject(Object obj) 方法可对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。 ObjectInputStream 代表对象输入流: 它的 readObject() 方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返 回。

结果展示:

person 对象序列化成功!
person 对象反序列化成功!
Person{name=‘bit’, age=10, sex=‘男’, stuId=0, count=99}

结果分析:

1,他实现了对象的序列化和反序列化。
2,transient 修饰的属性,是不会被序列化的 。我们的 stuId 本应是100,可现在为0.注意:内置类型 为对应0值。引用类型为null;
3、静态变量 好像也被序列化了,但是其实并没有。

5. 关于静态数据属性是否被序列化的测试

其他代码不变,主函数调用改为如下形式,并且将类中的count变量值改为888:

public static void main(String[] args) throws Exception {  
  //serializePerson();  
    Person person = deserializePerson();    
    System.out.println(person.toString()); 
}

运行结果展示:

person 对象反序列化成功! Person{name=‘bit’, age=10, sex=‘男’, stuId=0,count=888}

我们可以看到:count的值为888.

因为我们现在的情况是:

1、没有再进行序列化,直接进行反序列化
2、只是改变类中的count变量的值
如果是静态变量参与序列化,那么这个值不应该是888.应该还是上一次序列化的结果99.

结论:
静态变量的值是不会被进行序列化的。

6.关于serialVersionUID的问题

将上述代码再执行一遍运行(序列化和反序列化均要执行),接着将Person类中的 private static final long serialVersionUID = 1L;注释取消,然后屏蔽掉序列化的方法: serializePerson() ,运行主函数。

目的:当我们在类中没有指定 serialVersionUID 的时候,编译器会自动赋值,如果序列化是以默认 的 serialVersionUID ,那么反序列化也是会以那个默认的。而我们现在的情况是,以默认的 serialVersionUID 进行序列化,以自己赋值的 serialVersionUID 进行反序列化,这样代码就会出问 题。

代码示例:

public static void main(String[] args) throws Exception {  
  //serializePerson();  
    Person person = deserializePerson();    
    System.out.println(person.toString()); 
}

结果展示:

Exception in thread “main” java.io.InvalidClassException: Person;
local class incompatible: stream classdesc serialVersionUID = -5

注意这个异常: java.io.InvalidClassException

7.总结

1、一个类如果想被序列化,那么需要实现一个Serializable接口。
2、类中的静态变量的值是不会被进行序列化的,transient 修饰的属性,是不会被序列化的,内置类型 为对应0值。引用类型为null;
3、在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值,最好设置为1L,这 个L最好大写来区分,不然小写看起来像是1,不同的 serialVersionUID 的值,会影响到反序列化 .


转载:https://blog.csdn.net/qq_45691220/article/details/106954049
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场