开始时间: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