JavaSE——IO流5:高级流(序列化与反序列化流/对象操作流)

目录

一、序列化流/对象操作输出流——ObjectOutputStream

二、反序列化流/对象操作输入流——ObjecInputStream

三、序列化流和反序列化流使用细节

1.Serializable接口

2.序列化后的文件不可修改

3.serialVersionUID

4.transient修饰的不能被序列化

5.static修饰的属性是属于类的,不是属于对象的,所以不会被序列化

6.集合和映射(Map)的序列化

四、用对象流读写多个对象


序列化流            ObjectOutputStream        OutputStream

反序列化流        ObjecInputStream             InputStream

一、序列化流/对象操作输出流——ObjectOutputStream

序列化流可以把Java对象写到本地文件中 

注意:使用对象输出流将对象保存到文件时会出现NotSerializableException异常。所以输出的对象必须实现Serializable接口。 

代码示例:

public class ObjectStreamDemo1 {
    public static void main(String[] args) throws IOException {
        // 需求:利用序列化流/对象操作输出流,把一个对象写到本地文件中
        // 1.创建对象
        Student student = new Student("张三", 25);
        // 2.创建序列化流的对象/对象操作输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chapter18\\src\\com\\testdemo\\myobjectstream\\a.txt"));
        // 3.写出数据
        oos.writeObject(student);
        // 4.释放资源
        oos.close();
    }
}

/**
 * Serializable接口里面是没有抽象方法,标记型接口
 * 一旦实现了这个接口,就表示当前的Student类可以被序列化
 * 理解:一个物品的合格证
 */
class Student implements Serializable {
    private String name;
    private int age;

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

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

运行结果:

二、反序列化流/对象操作输入流——ObjecInputStream

可以把序列化到本地文件中的对象,读取到程序中来

代码实现: 

public class ObjectStreamDemo2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1.创建反序列化流的对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("chapter18\\src\\com\\testdemo\\myobjectstream\\a.txt"));
        
        // 2.读取数据
        Object readObject = ois.readObject();
        // Student readObject = (Student)ois.readObject();  // 可以强转
        
        // 3.打印对象
        System.out.println(readObject);
        // Student{name='张三', age=25}
        
        // 4.释放资源
        ois.close();
    }
}

三、序列化流和反序列化流使用细节

1.Serializable接口

        使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。否则,会出现NotSerializableException异常。

2.序列化后的文件不可修改

        序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了。

修改序列化后的文件:

再次执行反序列化代码:

会抛出StreamCorruptedException异常

3.serialVersionUID

        当对象被序列化到本地文件后,如果继续修改类,反序列化会失败,原因是版本号不一样,需要将IDEA设置serialVersionUID。

        serialVersionUID:序列化版本号。

        每一个类在实现Serializable接口之后这个类中就会自动产生一个版本号。如果这个版本号没有被指定,那么java在编译的时候会根据当前类中的属性和方法进行计算。

        也就意味着当类中的属性或者方法产生变动的时候,版本号就会重新自动计算。序列化的时候版本号会随着对象一起序列化,当对象反序列化的时候,会拿着原来的版本号会最新的版本号进行比较,如果版本号一致,则反序列化成功,否则抛出异常InvalidClassException。

        鼠标悬浮在Student类上,点击后就会生成一个版本号,修改Student类也能反序列化成功。

        如果不定义serialVersionUID,会抛出InvalidClassException异常

        注意:版本号尽量最后定义,即在类定义完成后再定义版本号,因为版本号是根据当前类的成员生成的。

        定义版本号后,也可以修改类的内容,并且序列化和反序列化也能成功。

4.transient修饰的不能被序列化

        如果一个对象中的某个成员变量的值不想被序列化,就需要给该成员变量添加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。

5.static修饰的属性是属于类的,不是属于对象的,所以不会被序列化

6.集合和映射(Map)的序列化

        绝大部分的集合和映射(Map)不允许将其中包含的元素一起序列化出去,里面的元素大部分是transient修饰的,所以想要序列化,需要遍历这些集合和映射,一个一个序列化。

ArrayList:

LinkedList:

HashMap:

四、用对象流读写多个对象

public class ObjectStreamDemo3 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        System.out.println("----------------序列化---------------");
        
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chapter18\\src\\com\\testdemo\\myobjectstream\\b.txt"));
        ArrayList<Teacher> list = new ArrayList<>();
        list.add(new Teacher("zhangsan", 23, "南京"));
        list.add(new Teacher("lisi", 24, "北京"));
        list.add(new Teacher("wangwu", 26, "重庆"));
        oos.writeObject(list);
        oos.close();

        System.out.println("----------------反序列化---------------");
        
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("chapter18\\src\\com\\testdemo\\myobjectstream\\b.txt"));
        ArrayList<Teacher> teachers = (ArrayList<Teacher>) ois.readObject();
        for (Teacher teacher : teachers) {
            System.out.println(teacher);
        }
        /**
         * Teacher{name='zhangsan', age=23, address='南京'}
         * Teacher{name='lisi', age=24, address='北京'}
         * Teacher{name='wangwu', age=26, address='重庆'}
         */
        ois.close();
    }
}

class Teacher implements Serializable {
    
    private static final long serialVersionUID = 6030696901056953191L;
    
    private String name;
    private int age;
    private String address;

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

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值