JavaSE笔记22:IO流(三)

28 篇文章 1 订阅

IO流(三)

上一篇:IO流(二)

序列化与反序列化

  1. java.io.NotSerializableException: se4.bean.Student
    Student对象不支持序列化!
  2. 参与序列化和反序列化的对象,必须实现Serializable接口
  3. 注意:通过源代码发现,Serializable接口只是一个标志接口:
    public interface Serializable {
    }
    这个接口当中什么代码都没有
    作用:起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇
    Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口后,会为该类自动生成一个序列化版本号
    在这里插入图片描述
package se4.file;

import se4.bean.Student;

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

public class ObjectOutputStreamTest01 {
    public static void main(String[] args) throws Exception {
        //创建Java对象
        Student s = new Student(1,"张三");
        //序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
        //序列化对象
        oos.writeObject(s);
        //刷新
        oos.flush();
        //关闭
        oos.close();
    }
}
package se4.bean;

import java.io.Serializable;

public class Student implements Serializable {
    //java虚拟机看到这个Serializable接口后,会为Student类自动生成一个序列化版本号
    //这里没有手动写出来,java虚拟机会默认提供序列化版本号
    private int no;
    private String name;

    public Student() {}

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

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}
package se4.file;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
/*
反序列化
 */
public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream  ois = new ObjectInputStream(new FileInputStream("students"));
        //开始反序列化,读
        Object obj = ois.readObject();
        //反序列化回来是一个学生对象,所以会调用学生对象的toString方法
        System.out.println(obj);//Student{no=1, name='张三'}
        ois.close();
    }
}

一次序列化多个对象
注意:参与序列化的ArrayList集合以及集合中元素Users都需要实现java.io.Serializable接口

package se4.file;

import se4.bean.Users;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception{
        List<Users> userList = new ArrayList<>();
        userList.add(new Users(1,"张三"));
        userList.add(new Users(2,"李四"));
        userList.add(new Users(3,"王五"));
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));
        //序列化一个集合,这个集合对象中放了许多其他对象
        oos.writeObject(userList);
        //刷新、关闭
        oos.flush();
        oos.close();
    }
}
package se4.bean;

import java.io.Serializable;

public class Users implements Serializable {
    private int no;
    private String name;

    public Users() {
    }

    public Users(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Users{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}
package se4.file;

import se4.bean.Users;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;
/*
反序列化集合
 */
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("users"));
        //Object obj = ois.readObject();
        //System.out.println(obj instanceof List);
        List<Users> usersList = (List<Users>)ois.readObject();
        for (Users users : usersList){
            System.out.println(users);
        }
        /**
         * 输出结果:
         * Users{no=1, name='张三'}
         * Users{no=2, name='李四'}
         * Users{no=3, name='王五'}
         */
        ois.close();
    }
}

transient关键字

transient关键字表示游离的,不参与序列化

public class Users implements Serializable {
    private int no;
    private transient String name;//name不参与序列化
}

关于序列化版本号

java语言中是采用什么机制来区分类的?
第一:首先通过类名进行比对
第二:若类名一样,靠序列化版本号进行区分

自动生成的序列化版本号的缺陷:

一旦代码确定之后,不能进行后续的修改,只有修改,必然会重新编译。此时会生成新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。

结论:

凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号,这样以后即使这个类代码修改了,版本号不变,Java虚拟机还会认为是同一个类。

public class Student implements Serializable {
    //java虚拟机看到这个Serializable接口后,会为Student类自动生成一个序列化版本号
    //这里没有手动写出来,java虚拟机会默认提供序列化版本号
    //建议将序列化版本号手动写出来,不建议自动生成
    private static final long serialVersionUID = 173173173;

    private int no;
    private String name;
    /*
    假设过了很久,Student类源代码改动了
    源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件
    并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变
    */
    private int age;
    private String email;
    private String address;
}

若没有手写序列化版本号改了代码会出现如下错误:

/*
java.io.InvalidClassException: se4.bean.Student;local class incompatible: stream classdesc serialVersionUID = -2006934289855497678, (假设是十年后)local class serialVersionUID = 6865918940855708725(假设是十年前)
*/

IO和Properties联合使用

IO流:文件的读和写

Properties:是一个Map集合,key和value都是String类型

package se4.io;

import java.io.FileReader;
import java.util.Properties;

/*
IO+Properties的联合应用

以后经常改变的数据可以单独写到一个文件中,使用程序动态读取,将来只需要修改这个文件的内容,java代码
不需要改动,不需要重新编译,服务器也不需要重启,就可以拿到动态的信息。

类似于以上机制的这种文件被称为配置文件,并且当配置文件中的内容格式是key1=value、key2=value的时候,
我们把这种配置文件叫做属性配置文件。

java规范中有要求:属性配置文件建议以.properties结尾,但这不是必须的。
 */
public class IoPropertiesTest01 {
    public static void main(String[] args) throws Exception {
        /*
        Properties是一个Map集合,key和value都是String类型
        想将userinfo文件中的数据加载到Properties对象中
         */
        //新建一个输入流对象
        FileReader reader = new FileReader("E:\\学习资料\\老杜Java系列\\Code\\userinfo");
        //新建一个Map集合
        Properties pro = new Properties();
        //调用Properties对象的load方法将文件中的数据加载到Map集合中
        pro.load(reader);//文件中的数据顺着管道加载到Map集合中,其中的等号(=)左边做key,右边做value
        //通过key获取value
        String username = pro.getProperty("username");
        System.out.println(username);//root

        String password = pro.getProperty("password");
        System.out.println(password);//123
    }
}

userinfo.properties文件

username=root
password=123
#在属性配置文件中井号是注释
#属性配置文件key重复的话,value会自动覆盖
#password=456

#最好不要有空格,可能会出现问题
#data = 100
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值