序列化和反序列化详解.

一、序列化和反序列化的理解

 序列化代码演示如下:(内存----> 硬盘文件)

student类:

package com.bjpowernode.java.io;
import java.io.Serializable;

// 序列化对象必须实现Serializable接口 起到标志性作用
public class Student implements Serializable {

    // 属性
    private String name;
    private int age;

    // 构造方法
    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // getter and setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // toString方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

代码测试如下:

package com.bjpowernode.java.io;
/*
    1、java.io.NotSerializableException异常

    2、参加序列化和反序列化的对象,必须实现Serializable接口
        此接口起到标志性作用,是给java虚拟机看的,java虚拟机看到这个接口后,会为该类自动生成一个序列化版本号
 */

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamTest01 {
    public static void main(String[] args) throws IOException {
        // 创建java对象
        Student student =new Student("junker",5);
        // 创建序列化对象
        ObjectOutputStream objectOutputStream =new ObjectOutputStream(new FileOutputStream("students"));
        // 序列化对象
        objectOutputStream.writeObject(student);

        // 刷新
        objectOutputStream.flush();
        // 关流
        objectOutputStream.close();
    }
}

结果:

 反序列化代码演示如下:

package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

// 反序列化: 文件----> 内存
public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        // 创反序列化对象
        ObjectInputStream objectInputStream =new ObjectInputStream(new FileInputStream("students"));
        // 开始反序列化 读
        Object o =objectInputStream.readObject();
        System.out.println(o);
        // 关流
        objectInputStream.close();
    }
}

输出结果:

 二、序列化多个对象

代码演示如下:

package com.bjpowernode.java.io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws IOException {
        // 创建一个集合
        ArrayList<User> arrayList =new ArrayList<>();
        // 向集合中添加元素
        arrayList.add(new User("kitty",5));
        arrayList.add(new User("junker",9));

        // 创建序列化对象
        ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("users"));
        // 序列化
        oos.writeObject(arrayList);

        // 刷新
        oos.flush();
        // 关流
        oos.close();
    }

}

结果:

 反序列化多个对象

代码演示如下:

package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

// 反序列化  文件》内存
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建反序列化对象
        ObjectInputStream ois =new ObjectInputStream(new FileInputStream("users"));
        // 反序列化
        // Object o =ois.readObject();    // 读到的是集合 因为存的时候就是集合
        // System.out.println(o instanceof List);  // true
         List<User> list =(List<User>)ois.readObject();
         for (User data :list){
             System.out.println(data);
         }
    }
}

输出结果: 

 三、transient关键字

package com.bjpowernode.java.io;
import java.io.Serializable;

public class User implements Serializable {

    // 属性
    transient String name;  // transient 不参于序列化 结果 null
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

反序列化后的输出结果:

 四、关于序列化版本号

 假设这个User类是我们很久以前写的业务:

package com.bjpowernode.java.io;
import java.io.Serializable;

public class User implements Serializable {
/*
java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
    // 这里没有手动写出来,java虚拟机会默认提供这个序列化版本号
*/

    // 属性
    String name;
    int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;

    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 我们通过序列化把它存入到了文件当中

package com.bjpowernode.java.io;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

// 序列化  内存----> 文件
public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws IOException {
        // 创建一个集合
        ArrayList<User> arrayList =new ArrayList<>();
        // 向集合中添加元素
        arrayList.add(new User("kitty",5));
        arrayList.add(new User("junker",9));

        // 创建序列化对象
        ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("users"));
        // 序列化
        oos.writeObject(arrayList);

        // 刷新
        oos.flush();
        // 关流
        oos.close();
    }
}

现在我们假定对User这个类当中做了优化/改进 那么我们通过反序列化这个users文件会是什么情况?

报错: java.io.InvalidClassException: stream classdesc serialVersionUID = 7674971421060302263, local class serialVersionUID = -7731114658773239639 

通过报错可以看出第一个序列化版本号和我们修改完User类再次自动生成的序列化版本号不同了

解决方案: 我们可以手动把序列化版本号定义成第一个JVM机看到Serialzable后自动生成的序列化版本号 然后不管我们以后怎么优化修改User类 序列化版本号都是这一个 就可以进行反序列化了

package com.bjpowernode.java.io;
import java.io.Serializable;

public class User implements Serializable {
    
    // 属性
    String name;
    int age;
    private String addr;    // 假定现在优化了User这个类
    

    public User(String name, int age) {
        this.name = name;
        this.age = age;

    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

反序列化该文件:

package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

// 反序列化  文件----> 内存
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建反序列化对象
        ObjectInputStream ois =new ObjectInputStream(new FileInputStream("users"));
        // 反序列化
        // Object o =ois.readObject();
        // System.out.println(o instanceof List);  // true
         List<User> list =(List<User>)ois.readObject();
         for (User data :list){
             System.out.println(data);
         }
        }
}

原因:

package com.bjpowernode.java.io;
import java.io.Serializable;

public class User implements Serializable {

 /*
    原因: java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号
    // 这里没有手动写出来,java虚拟机会默认提供这个序列化版本号

     */

    // 手动定义成和JVM自动生成的第一个序列化版本号序列化版本号
    private static final long serialVersionUID = 7674971421060302263L;

    // 属性
    String name;
    int age;

    private String addr;    // 假定现在优化了User这个类

    // 过了很久,User这个类源代码改动了
    // 源代码改动后需要重新编译,编译之后生成了全新的字节码文件
    // 并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变
    // (相当于第一个User implements Serializable 这个类没修改前是两个属性 name 、age java虚拟机看到Serializable接口之后自动生成
    // 一个序列化版本号      当我们修改这个User implements Serializable这个类之后 不再和第一个类一样,java虚拟机看到Serializable接口
    // 后又会自动生成一个序列化版本号  修改前后的序列化版本号不同 所以当我们再次反序列化此文件的时候就会出现报错异常)

    // 解决方案: 我们可以手动定义一个序列化版本号,让User这个类修改前后的序列化版本号固定一样,那么我们就可以反序列化了


    public User(String name, int age) {
        this.name = name;
        this.age = age;

    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}



手动定义序列化版本号后反序列化结果:

package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

// 反序列化  文件----> 内存
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 创建反序列化对象
        ObjectInputStream ois =new ObjectInputStream(new FileInputStream("users"));
        // 反序列化
        // Object o =ois.readObject();
        // System.out.println(o instanceof List);  // true
         List<User> list =(List<User>)ois.readObject();
         for (User data :list){
             System.out.println(data);
         }
        }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值