JDK框架简析--java.io包中的输入输出类库


题记


JDK,Java Development Kit。

我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下的rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平。

本系列所有文章基于的JDK版本都是1.7.16。


本节内容


Java IO库提供了一个可以称之为链接的机制,可以将一个流与另一个流首尾衔接,形成一个流管道的链接。这种机制实际上是装饰模式(Decorator)的应用。

通过流的链接,可以动态的增加流的功能,而这种功能的增加,是通过动态的组合一些流的基本功能获取的。

我们要获取一个IO对象,往往要产生多个IO对象,这也是Java IO库不太容易掌握的地方,但这种在IO库中Decorator模式的运用,给我们提供了实现上的灵活性。


流的分类


节点流:从特定的地方读写的流类,比如磁盘或内存;比如FileInputStream/FileOutputStream就是节点流。

过滤流:使用节点流作为输入输出,提供功能的增强,继承自FilterInputStream/FilterOututStream的类(比如DataInputStream提供读写Java基本数据类型的能力,BufferedInputStream提供数据缓存的能力)。

管道流:用于线程间的通信,比如PipedInputStream/PipedOutputStream。


演示一个功能增强的流程:


File  --》FileInputStream(从文件中读取字节) --》 BufferedInputStream(增加了缓冲功能)--》DataInputStream(增加了读取Java基本数据类型的能力)--》数据

数据 --》DataInputStream(输出流写入Java基本类型)--》BufferedOutputStream(提供数据写入缓冲区的功能)--》FileOutputStream(写入文件)--》File


字节流和字符流:


Java语言使用Unicode来表示字符。

Reader和Writer主要用来读写字符。


对象序列化


将对象转化为字节流保存起来,并在日后还原这个对象,这种机制叫做对象序列化。

将一个对象保存到永久存储设备上,叫做持久化。

一个对象要想能够实现序列化,必须实现java.io.Serializable接口,这个接口是一个声明式接口,没有任何内容,只是告诉编译器,对象是可以序列化的。

当一个对象被序列化时,只保留这个对象的非静态成员变量,不能保存任何成员方法和静态的成员变量。

如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。

如果一个可序列化的对象包含对某个不可序列化的对象的成员变量的引用,那么整个序列化操作会失败,并且抛出一个异常:java.io.NotSerializableException。我们可以将这个引用标记为transient,那么这个对象也可以序列化。因为用transient关键字标记的变量,在序列化时,会被抛弃。


serialVersionUID


Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。

(1)实现了Serializable接口的对象,可以显示设置serialVersionUID的值(JDK源码中就是这么干的)

(2)也可以不设置serialVersionUID的值,这时,Java序列化机制会根据编译的class(它通过类名,方法名等诸多因素经过计算而得,理论上是一一映射的关系,也就是唯一的)自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果class文件(类名、方法等)没有发生变化,增加空格、换行、注释是可以的,编译多次,serialVersionUID也不会变化的;如果增加了方法、变量等,则会报异常:java.io.InvalidClassException

(3)日常生产中,我们经常这么设置:private static final long serialVersionUID = 1L; 这时,Java序列化机制会认为版本是一致的,只会对能对照起来的变量进行赋值,对于类和序列化的数据中不一致的地方(比如序列化之后,类增加减少了字段),会直接抛弃


对象序列化代码演示


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;

public class Test {
	public static void main(String[] args) throws Exception {		

		serial();
		Person p = deserial();
		System.out.println(p.getName());
		System.out.println(p.getAge());

	}
	
	private static void serial() throws Exception {
		Person p = new Person("zhangsan",18);		
		FileOutputStream fos = new FileOutputStream("/Users/puma/tt/person.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(p);
		oos.flush();
		oos.close();
	}
	
	private static Person deserial() throws Exception{
		FileInputStream fis = new FileInputStream("/Users/puma/tt/person.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Person p = (Person)ois.readObject();
		return p;
	}
}
class Parent implements Serializable {}
class Person extends Parent {
	private static final long serialVersionUID = 1L;
	private String name;
	private Integer age;
	public Person(String name,Integer age) {
		this.setName(name);
		this.setAge(age);
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。