java 序列化流、打印流

第一章 序列化

1.1 概述

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据 、对象的类型和对象中存储的属性 等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、 对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化

1.2 ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

构造方法
public ObjectOutputStream(OutputStream out) : 创建一个指定OutputStream的ObjectOutputStream

构造举例,代码如下:

FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

序列化操作

  1. 一个对象要想序列化,必须满足两个条件:
  • 该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出 NotSerializableException
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用 transient 关键字修饰。
public class Employee implements Serializable {
	public String name;
	public String address;
	public transient int age; // transient瞬态修饰成员,不会被序列化
	public void addressCheck() {
		System.out.println("Address check : " + name + " ‐‐ " + address);
	}
}
  1. 写出对象方法
    public final void writeObject (Object obj) : 将指定的对象写出。
public class SerializeDemo{
	public static void main(String [] args) {
		Employee e = new Employee();
		e.name = "zhangsan";
		e.address = "beiqinglu";
		e.age = 20;
		try {
			// 创建序列化流对象
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
			// 写出对象
			out.writeObject(e);
			// 释放资源
			out.close();
			fileOut.close();
			System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年龄没有被序列
化。
		} catch(IOException i) {
			i.printStackTrace();
		}
	}
}
输出结果:
Serialized data is saved

1.3 ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

构造方法
public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream。

反序列化操作1:
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法: public final Object readObject () : 读取一个对象。

public class DeserializeDemo {
	public static void main(String [] args) {
		Employee e = null;
		try {
			// 创建反序列化流
			FileInputStream fileIn = new FileInputStream("employee.txt");
			ObjectInputStream in = new ObjectInputStream(fileIn);
			// 读取一个对象
			e = (Employee) in.readObject();
			// 释放资源
			in.close();
			fileIn.close();
		}catch(IOException i) {
			// 捕获其他异常
			i.printStackTrace();
			return;
		}catch(ClassNotFoundException c) {
			// 捕获类找不到异常
			System.out.println("Employee class not found");
			c.printStackTrace();
			return;
		}
		// 无异常,直接打印输出
		System.out.println("Name: " + e.name); // zhangsan
		System.out.println("Address: " + e.address); // beiqinglu
		System.out.println("age: " + e.age); // 0
	}
}

对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

反序列化操作2
另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操 作也会失败,抛出一个 InvalidClassException 异常。发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法

Serializable接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序 列化的对象和对应类是否版本匹配。
在这里插入图片描述

public class Employee implements java.io.Serializable {
	// 加入序列版本号
	private static final long serialVersionUID = 1L;
	public String name;
	public String address;
	// 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
	public int eid;
	
	public void addressCheck() {
		System.out.println("Address check : " + name + " ‐‐ " + address);
	}
}

1.4 练习:序列化集合

  1. 将存有多个自定义对象的集合序列化操作,保存到 list.txt 文件中。
  2. 反序列化 list.txt ,并遍历集合,打印对象信息。

案例分析
把若干学生对象 ,保存到集合中。

  1. 把集合序列化。
  2. 反序列化读取时,只需要读取一次,转换为集合类型。
  3. 遍历集合,可以打印所有的学生信息

案例实现:

public class SerTest {
	public static void main(String[] args) throws Exception {
		// 创建 学生对象
		Student student = new Student("老王", "laow");
		Student student2 = new Student("老张", "laoz");
		Student student3 = new Student("老李", "laol");
		
		ArrayList<Student> arrayList = new ArrayList<>();
		arrayList.add(student);
		arrayList.add(student2);
		arrayList.add(student3);
		
		// 序列化操作
		// serializ(arrayList);
		// 反序列化
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));
		// 读取对象,强转为ArrayList类型
		ArrayList<Student> list = (ArrayList<Student>)ois.readObject();

		for (int i = 0; i < list.size(); i++ ){
			Student s = list.get(i);
			System.out.println(s.getName()+"‐‐"+ s.getPwd());
		}
	}
	
	private static void serializ(ArrayList<Student> arrayList) throws Exception {
		// 创建 序列化流
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));
		// 写出对象
		oos.writeObject(arrayList);
		// 释放资源
		oos.close();
	}
}

第二章 打印流

2.1 概述

平时我们在控制台打印输出,是调用 print 方法和 println 方法完成的,这两个方法都来自于 java.io.PrintStream 类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式

2.2 PrintStream类

构造方法 :
public PrintStream(String fileName) : 使用指定的文件名创建一个新的打印流。

PrintStream ps = new PrintStream("ps.txt")

改变打印流向:
System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然是流对象, 我们就可以玩一个"小把戏",改变它的流向。

public class PrintDemo {
	public static void main(String[] args) throws IOException {
		// 调用系统的打印流,控制台直接输出97
		System.out.println(97);
		
		// 创建打印流,指定文件的名称
		PrintStream ps = new PrintStream("ps.txt");
		
		// 设置系统的打印流流向,输出到ps.txt
		System.setOut(ps);
		
		// 调用系统的打印流,ps.txt中输出97
		System.out.println(97);
	}
}
发布了37 篇原创文章 · 获赞 30 · 访问量 1142

猜你喜欢

转载自blog.csdn.net/myjess/article/details/104295096