Day20-2.对象序列化流、Properties

1 对象序列化流

  1. 相关概念:
    (1)数据的状态:
    游离态:在运行内存中保存的数据。随着程序的结束,数据也会被回收
    持久态:在磁盘中进行保存的数据。随着程序的结束,随着计算机的关机和开机, 数据并不会消失。
    (2)序列化:
    将数据从运行内存中(游离态),输出到磁盘中保存(持久态)
    输出数据:序列化
    (3)反序列化:
    将数据从磁盘中(持久态),输入到运行内存中使用(游离态)
    读取数据:反序列化
  2. 序列化流的使用:
    构造方法:
    ObjectOutputStream(OutputStream out):将一个输出流,封装为一个对象序列化流
    序列化对象方法:
    ` ``void writeObject(Object obj)```:将指定对象写出到流中传输
  3. 注意:
    (1)保留对象的文件,无法看懂,作用是存储对象数据,不能进行查看
    (2)如果需要序列化一个对象,那么这个对象所属的类型,需要实现一个 Serializable接口
    (3)Serializable接口:
    接口中没有任何属性和方法,它是一个标记接口
    只有实现这个接口的类型,才可以进行序列化和反序列化
  4. 反序列化流的使用:
    构造方法:
    ObjectInputStream(InputStream inp):将一个输入流,封装为一个对象序列化流
    反序列化对象方法:
    void readObject():将对象从文件中读取到内存中
  5. 序列化ID:
    serialVersionUID:
    (1)用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取 数据会不会出问题呢?
    会出问题,会抛出InvalidClassException异常
    (2)如果出问题了,如何解决呢?
    重新序列化
    给对象所属的类加一个serialVersionUID
    格式为:private static final long serialVersionUID = 42L;
  6. transient关键字:
    如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
    给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。

代码1

package demos5;

import java.io.*;

public class Demo01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        //反序列化:将对象数据从磁盘中读取的运行内存中
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day20/pers.txt"));
        Person o = (Person)ois.readObject();
        System.out.println(o);
    }

    private static void test() throws IOException {
        Person p = new Person("张三",23);
        //序列化:将一个对象输出到目标文件中永久保存
        //注意:保存的是一个对象(不是一个字符串)
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day20/pers.txt"));
        oos.writeObject(p);
        oos.close();
    }
}

//如果该类型的对象需要输入和输出,那么该类型就必须实现该接口
//该接口没有任何特殊的功能,仅仅表示一个标记性接口
//public class Person implements Serializable {

代码2

package demos5;

import java.io.*;
import java.util.ArrayList;

public class Demo02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day20/pers.txt"));
        //读取文件中保存的一个对象,对象是一个集合对象
        ArrayList<Person> o = (ArrayList<Person>)ois.readObject();
        //遍历读取的集合对象,获取集合中的每一个数据
        for(Person p:o){
            System.out.println(p);
        }
        ois.close();
    }

    private static void test() throws IOException {
        Person p = new Person("张三",23);
        Person p2 = new Person("李四",24);
        Person p3 = new Person("王五",25);
        //创建一个集合,用来存储需要输出的多个对象
        ArrayList<Person> list = new ArrayList<>();
        list.add(p);
        list.add(p2);
        list.add(p3);
        //序列化:将一个对象输出到目标文件中永久保存
        //注意:保存的是一个对象(不是一个字符串)
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day20/pers.txt"));
        //直接将集合对象进行输出
        //所以文件中保存了一个对象:集合对象
        oos.writeObject(list);
        oos.close();
    }
}

代码3

package demos5;

import java.io.Serializable;
import java.util.Objects;

//如果该类型的对象需要输入和输出,那么该类型就必须实现该接口
//该接口没有任何特殊的功能,仅仅表示一个标记性接口
public class Person implements Serializable {
    //如果一个类型实现接口之后,默认给该类型提供一个序列化ID:serialVersionUID
    //在改变类型之前,该类型有一个默认的ID:4534052414420698388
    //在改变之后,类型有一个新的默认ID:-851914110996954230
    //问题:类型改变之后,不能使用该类型接收之前输出的对象
    //原因:因为改变类型前后,类型的ID不同,所以不能使用改变后的类型接收改变前的对象
    //解决方案:
    //在实现该接口之后,主动给一个固定的ID:
    private static final long serialVersionUID = 100L;
    //给定一个固定的id之后,系统不会默认提供
    //即使修改了类型的内容,只要id一样,就认为是同一个类型,就可以正常接收
    private String name;
    private int age;
    private String hobby;

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

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

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

    public Person() {
    }

    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;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

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

2 Properties

  1. 概述:
    是一个双列集合,是一个Map体系的集合类,是Hashtable的子类

2.1 Properties特殊方法

函数Value
setProperty(String key, String value)添加键值对
getProperty(String key)根据指定的键获取对应的值
stringPropertyNames()将集合中的键获取到一个单列集合Set中进行存储

2.2 Properties和IO流相结合的方法

函数Value
load(Reader reader)从输入字符流读取属性列表(键和元素对)
load(InputStream in)从输入字节流读取属性列表(键和元素对)
store(Writer writer, String comments)将此属性列表(键和元素对)写入Properties文件
store(OutputStream out, String comments)将此属性列表(键和元素对)写入Properties

代码

package demos6;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;

public class Demo02 {
    public static void main(String[] args) throws IOException {

       Properties pro = new Properties();
       //创建一个字符输入流
       FileReader fr = new FileReader("day20/pro.properties");
       //将文件中的数据,读取到集合中保存
       pro.load(fr);
       System.out.println(pro);
//        test();
    }
    private static void test() throws IOException {
        Properties pro = new Properties();
        pro.setProperty("name","张三");
        pro.setProperty("age","23");
        pro.setProperty("hobby","学习");
        //创建一个字符输出流
        FileWriter fw = new FileWriter("day20/pro.properties");
        //将集合中的键值对数据写出到目标文件中保存
        pro.store(fw,"");
        fw.close();
    }
}

3 练习1:

需求:
(1)在Properties文件中有如下信息:
name=张三
age=18
hobby=玩游戏
(2)将数据读取到集合中
(3)将读取的数据封装成一个学生对象,将该对象输出本地文件中永久保存

代码

package demos6;

import java.io.*;
import java.util.Properties;

public class Test01 {
    public static void main(String[] args) throws IOException {

        Properties pro = new Properties();
        FileReader fr = new FileReader("day20/pro.properties");
        pro.load(fr);
        fr.close();
        Stu s = new Stu(pro.getProperty("name"),pro.getProperty("age"),pro.getProperty("hobby"));

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day20/a.txt"));
        oos.writeObject(s);
        oos.close();

    }
}

4 练习2:

(1)在Properties文件中有如下信息:
name=张三
age=18
hobby=玩游戏
(2)将该文件中的name=张三,改为name=李四
(3)要求:使用代码完成内容的修改

代码

package demos6;

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

public class Test02 {
    public static void main(String[] args) throws IOException {

        Properties pro = new Properties();
        FileReader fr = new FileReader("day20/pro.properties");
        pro.load(fr);
        fr.close();
        pro.setProperty("name","李四");
        System.out.println(pro);

        FileWriter fw = new FileWriter("day20/pro.properties");
        pro.store(fw,"");
        fw.close();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值