java复习第8天---8.6---IO流---序列化流和打印流


目录




内容

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、序列化操作

  • 满足的条件:

    1. 该类必须实现java.io.Serializable接口,Serializable接口是序列化标记,不实现此接口的类的任何状态不会被序列化和反序列化。
    2. 该类是所有属性必须是可序列化的。如果有一个类型不需要序列化,必须注明是瞬态的,使用transient关键字声明。
  • 使用步骤:

    1. 创建ObjectOutputStream对象
    2. 调用ObjectOutputStream类的writeObject 方法,把对象写入文件中
    3. 释放资源
  • 示例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读取一个对象。
  • 使用步骤:

    1. 创建ObjectOutputStream对象
    2. 调用ObjectOutputStream类的writeObject 方法,把对象写入文件中
    3. 释放资源
  • 示例: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为其他输出流添加了功能,使它们能够方便的打印各数据值表示形式。

  • 特点

    1. 只负责数据的输出,不负责数据的读取
    2. 与其它输出流不同,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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章