目录
文章目录
内容
1、序列化流
1.1、序列化概述
之前我在存储数据的时候,都是基本数据类型。但是当我们想要存储对象的时候怎么办呢?Java提供了一种对象序列化机制。用一个字节序列表示一个对象,包括对象类信息,成员变量、成员方法信息等,然后写入磁盘或者其他流中,相当于文件中持久化了一个对象,称为对象的序列化。
反之,该字节序列还可以读取文件中的对象信息,重构对象,称之为对象的反序列化。
- 图示1.1-1:
1.2、ObjectOutputStream
java.io.ObjectOutputStream类,把Java对象的原始数据类型持久化到文件中。
- 构造方法
参数列表 | 描述 |
---|---|
OutputStream out | 创建一个写入指定的OutputStream的ObjectOutputStream |
- 常用方法
修饰符 | 返回值类型 | 方法名 | 参数列表 | 描述 |
---|---|---|---|---|
public | void | writeObject | Object obj | 将指定的对象写入ObjectOutputStream。 |
1.2.1、序列化操作
-
满足的条件:
- 该类必须实现java.io.Serializable接口,Serializable接口是序列化标记,不实现此接口的类的任何状态不会被序列化和反序列化。
- 该类是所有属性必须是可序列化的。如果有一个类型不需要序列化,必须注明是瞬态的,使用transient关键字声明。
-
使用步骤:
- 创建ObjectOutputStream对象
- 调用ObjectOutputStream类的writeObject 方法,把对象写入文件中
- 释放资源
-
示例1.2.1-1:
package io.stream.serialize; import java.io.Serializable; public class Student implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String name; private int age; private char gender; private int score; public Student() {} public Student(String name, int age, char gender, int score) { this.name = name; this.age = age; this.gender = gender; this.score = score; } 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; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } @Override public String toString() { return name + "\t" + age + "\t" + gender + "\t" + score; } } package io.stream.serialize; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class TestSeriabliable1 { public static void main(String[] args) throws FileNotFoundException, IOException { Student s = new Student("gaogzhen", 32, '男', 8000); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\test\\b.txt")); oos.writeObject(s); oos.close(); } } 测试结果:b.txt内容 sr io.stream.serialize.Student I ageC genderI scoreL namet Ljava/lang/String;xp u7 @t gaogzhen 字节码文件,直接打开,看不懂
1.3、ObjectInputStream
&esmp; ObjectInputStream类,把之前ObjectOutputStream类序列化到文件中的对象,反序列化之后,重构为对象。
- 构造方法:
参数列表 | 描述 |
---|---|
InputStream in | 创建从指定的InputStream读取的ObjectInputStream。 |
- 常用方法
修饰符 | 返回值类型 | 方法名 | 参数列表 | 描述 |
---|---|---|---|---|
public | Object | readOject | 从ObjectInputStream读取一个对象。 |
-
使用步骤:
- 创建ObjectOutputStream对象
- 调用ObjectOutputStream类的writeObject 方法,把对象写入文件中
- 释放资源
-
示例:1.3-1:读取b.txt序列化的对象并显示
package io.stream.serialize; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; public class TestUnSerialize1 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\test\\b.txt")); Student s = (Student) ois.readObject(); ois.close(); System.out.println(s); } } 测试结果: gaogzhen 32 男 8000
1.4、transient关键字
意为瞬态,被transient修饰的成员变量不能被序列化
-
示例1.4-1:
上例中的Student 的age 用transient修饰 private transient int age; package io.stream.serialize; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class TestTransient1 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { Student s = new Student("gaogzhen", 32, '男', 8000); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\test\\b.txt")); oos.writeObject(s); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\test\\b.txt")); Student s1 = (Student) ois.readObject(); ois.close(); System.out.println(s1); } } 测试结果: gaogzhen 0 男 8000
1.5、InvalidClassException
当JVM反序列化对象时,能找到class文件,但是class文件的序列化对象之后发生了修改,那么反序列化操作会失败,抛出InvalidClassException异常。发生此异常的原因:
- 该类的序列号于从六种读取的类描述符的版本号不匹配
- 该类包含未知的数据类型
- 该类没有可访问的无参构造函数
1.6、serialVersionUID
serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。
显式地定义serialVersionUID有两种用途:
1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。
2、打印流
java.io.PrintStream打印流。PrintStream为其他输出流添加了功能,使它们能够方便的打印各数据值表示形式。
-
特点
- 只负责数据的输出,不负责数据的读取
- 与其它输出流不同,PrintStream永远不会抛出IOException
-
特有方法
- void print(任意类型):打印任意类型的数据
- void println(任意类型):打印任意类型的数据,并且换行
-
构造方法
参数列表 | 描述 |
---|---|
File file | 输出目的地为文件 |
String fileName | 输出目的地文件 |
OutputStream out | 输出到其他流 |
- 继承自父类的方法
修饰符 | 返回值类型 | 方法名 | 参数列表 | 描述 |
---|---|---|---|---|
public | void | close | 关闭流,释放资源 | |
public | void | flush | 刷新此输出流,并强制任何缓冲的字节写出 | |
public | void | write | byte[] b | 将 b.length字节从指定的字节数组写入此输出流。 |
public | void | write | byte[] b, int off, int len | 从指定的字节数组写入 len个字节,从偏移 off开始到此流。 |
public abstract | void | write | int b | 将指定的字节写入此流。 |
-
注意:
- 如果使用继承自父类的write方法写数据,那么查看数据的时候会查看编码表
- 如果使用特有的print或者println方法写数据,原样输出
-
示例2-1:
package io.stream.print; import java.io.PrintStream; public class TestPrintStream1 { public static void main(String[] args) { PrintStream ps = new PrintStream(System.out); ps.write(97); ps.println(); ps.println(97); } } 测试结果: a 97
后记 :
本项目为参考某马视频开发,相关视频及配套资料可自行度娘或者联系本人。上面为自己编写的开发文档,持续更新。欢迎交流,本人QQ:806797785
前端项目源代码地址:https://gitee.com/gaogzhen/vue-leyou
后端JAVA源代码地址:https://gitee.com/gaogzhen/JAVA