JavaSE进阶590-597 序列化和反序列化/IO和Properties联合

开始时间:2021-01-05

对象的序列化和反序列化

将Java对象放在硬盘的操作->序列化(拆分对象) serialize
传的时候是一个数据包一个数据包的传,传的每个部分都有编号(应该用的是计算机网络的知识)
恢复的过程称为反序列化(组装对象)deserialize

这里插播一条消息
IntelliJ IDEA 对齐代码的快捷键是 Alt+Ctrl+L
但是我这两天用的时候发现没有作用了
查询了才知道是我最近下载了网易云音乐,需要在网易云音乐里把这个冲突的快捷键关掉。

package Test20210105;

import java.io.FileNotFoundException;
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 s = new Student(1111, "Zhangsan");
        //序列化
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("students"));
        //序列化对象,但是直接序列化是不行的,student类不支持序列化
        //所以需要让student类实现序列化接口Serializable
        //Serializable代码里面什么都没有,起到标识的作用,是标志接口,这类都没有方法的。但Java虚拟机看得懂
        //虚拟机会自动给对象生成序列化版本号
        objectOutputStream.writeObject(s);
        //刷新
        objectOutputStream.flush();
        //关闭
        objectOutputStream.close();
    }
}

package Test20210105;

import java.io.Serializable;

public class Student implements Serializable {
    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 Test20210105;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
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"));
        //调用readObject读取对象
        Object obj = objectInputStream.readObject();
        //反序列化后是一个学生对象,所以可以调用之前重写的学生对象的toString方法
        System.out.println(obj);
        objectInputStream.close();
    }
}

示例2:序列和反序列化多个对象(集合)

package Test20210105;

import java.io.Serializable;

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

    public User() {
    }

    public User(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 "User{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

}

package Test20210105;

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

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws IOException {
        List<User> userList = new ArrayList<>();
        userList.add(new User(01, "Zhangsan"));
        userList.add(new User(02, "Lisi"));
        userList.add(new User(03, "Wangwu"));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("users"));

        objectOutputStream.writeObject(userList);
        objectOutputStream.flush();
        objectOutputStream.close();
    }
}

package Test20210105;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;

/*
反序列化集合
 */
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("users"));
        //obj即为一个List集合
        Object obj = objectInputStream.readObject();
        List<User> userList = (List<User>) obj;
        for (User user : userList) {
            System.out.println(user);
        }
        objectInputStream.close();
    }
}

transient游离

在定义属性前加上他,就不会参与序列化了

    private int no;
    private transient String name;

输出

Student{no=1111, name='null'}

但如果我把Student类加一个属性

	private int no;
    private transient String name;
    private int age;

然后直接运行反序列程序
就会报错,序列号不一样了

Exception in thread "main" java.io.InvalidClassException: Test20210105.Student;
local class incompatible: stream classdesc serialVersionUID = 229214361083889462, 
local class serialVersionUID = -8821545700813961513

区分一个类是否为同一个,一个是看类名,另一个是看序列号
只要类实现了serializable接口,那么就会生成序列号,作为两个不同类的区分。
虚拟机能区分开序列号的。

缺陷就是改了代码后自动给你换新的序列号了,同一个类也会被认为是不同的类。

最终结论:
凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。
即使代码修改了,版本号还是不变

	//手动写序列号
    private static final long serialVersionUID = 20210105L;
    private int no;
    private transient String name;

这样先编译ObjectOutputStream,再修改Student的属性,然后反编译ObjectInputStream,仍然可以编译回来

IDEA自动生成唯一序列号

在这里插入图片描述

勾选后如果没有自己设置
那可以提示你用enter+alt来自动给一个唯一序列号

public class Student implements Serializable {
    private static final long serialVersionUID = 229214361083889462L;
    // private static final long serialVersionUID = 20210105L;

IO和Properties的联合使用

Properties是一个Map集合,key和value都是string类型。
例如在"E:\编程学习\Java学习\UserInfo.txt"写下下面两行
Username=Zhangsan
Password=123

将UserInfo文件中的数据加载到Properties对象当中,就可以用下面的代码

package Test20210105;

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

public class IOPropertiesTest01 {
    public static void main(String[] args) throws IOException {
        //将UserInfo文件中的数据加载到Properties对象当中
        FileReader fileReader = new FileReader("E:\\编程学习\\Java学习\\UserInfo.txt");
        //新建map集合
        Properties properties = new Properties();
        //文件中的数据加载到了map集合中,等号左边是key,右边是value
        //调用properties对象的load方法将文件中的数据加载到Map集合中。
        properties.load(fileReader);

        //通过key来获取value
        String username = properties.getProperty("Username");
        //像经常变化的数据,信息就不要写在Java程序里了,而是放在单独的文件中用Java程序来读取
        System.out.println(username);
    }
}

输出
在这里插入图片描述
如果改了用户名
在这里插入图片描述
输出也会相应更新
在这里插入图片描述

类似于以上机制的文件,叫做配置文件
并且当配置文件中的内容格式是:
key1=value
key2=value
key3:value
的时候,我们把这种配置文件叫做属性配置文件。
冒号等号都行,左边是key右边是value
java规范中有要求;属性配置文件建议以.properties结尾,但这不是必须的
#########在属性配置文件中井号是注释######
属性配置文件的key重复的话,value会自动覆盖!

结束时间:2021-01-05

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值