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