1.Filter模式
a.简介
i.直接使用继承,为各种InputStream附加更多功能,根本无法控制代码的复杂度,很快就会失控。
ii.为了解决依赖继承会导致子类数量失控的问题,JDK首先将InputStream分为两大类:
1.提供数据的基础的InputStream
a.FileInputStream:文件
b.ByteArrayInputStream:数组
c.ServletInputStream:网络
2.提供额外附加功能的InputStream
a.BufferedInputStream:缓冲
b.DigestInputStream:计算签名
c.CipherInputStream:加/解密
iii.通过一个“基础”组件再叠加各种“附加”功能组件的模式,称为Filter模式(或者装饰器模式:Decorator)。 它可以通过少量的类来实现各种功能的组合。
b.编写FilterInputStream
i.可以把自己的FilterInputStream叠加到任何一个InputStream中。
ii.叠加多个FilterInputStream,我们只需要持有最外层的InputStream。try(resource)语法,外层内层的InputStream的close()方法都会调用,所有资源都会关闭,因此不存在资源泄露。
iii.编写一个CountInputStream,对输入的字节进行计数。
c.总结
i.Java的IO标准库使用Filter模式为InputStream和OutputStream增加功能:
1.可以把一个InputStream和任意个FilterInputStream组合。
2.可以把一个OutputStream和任意个FilterOutputStream组合。
ii.Filter模式可以在运行期动态增加功能(又称Decoartor模式)。
2.序列化
a.简介
i.序列化是把一个Java对象变成二进制内容(byte[]数组);反序列化是把一个二进制内容(byte[]数组)变回Java对象。
ii.Java对象序列化后可以把byte[]保存到文件中,或把byte[]通过网络传输到远程。
iii.Java对象序列化,需实现java.io.Serializable接口。
iv.Serializable没有定义任何方法,是一个空接口,称为“标记接口”(Marker Interface),实现了标记接口的类仅仅是给自身贴了个“标记”,没有增加任何方法。
b.序列化
i.把一个Java对象变为byte[]数组,需要使用ObjectOutputStream。它负责把一个Java对象写入一个字节流。ObjectOutputStream可以写入基本类型,String,实现了Serializable接口的Object。
c.反序列化
i.ObjectInputStream负责从一个字节流读取Java对象。可以读基本类型和String,调用readObject()可以直接返回一个Object对象,要把它变成特定类型,必须强制转型。
ii.readObject()可能抛出的异常
1.ClassNotFoundException:没有对应的Class。即序列化时传的Person对象,在反序列化程序中没有。
2.InvalidClassException:Class不匹配。即序列化时Person类的age定义的是int,反序列化时Person类的age定义的是long,导致class不兼容。
iii.为避免这种class定义导致的不兼容,Java的序列化允许class定义一个特殊的serialVersionUID静态变量。
iv.反序列化时,由JVM直接构造出Java对象,不调用构造方法,构造方法内部的代码,在反序列化时根本不执行。
d.安全性
i.Java的序列化机制可以导致实例直接通过byte[]数组创建,不调用构造方法。byte[]数组被反序列化后可执行特定的代码,存在安全隐患。
ii.Java的序列化和反序列化机制即存在安全性问题,又存在兼容性问题。更好的序列化方法是通过JSON这样的通用数据结构来实现,只输出基本类型(包括String)的内容,不存储任何代码信息。
iii.序列化机制仅适应于Java,需要与其他语言交换数据,必须使用通用的序列化方法,例如JSON。
3.操作Zip
a.简介
i.ZipInputStream是一种FilterInputStream。
ii.ZipOutputStream是一种FilterOutputStream。
b.读取zip包
i.FileInputStream作为数据源,循环调用getNextEntry(),返回null,表示zip流结束。
ii.一个ZipEntry表示一个压缩文件或目录,如果是压缩文件,就用read()方法不断读取,返回-1表示结束。
c.写入zip包
i.ZipOutputStream可以直接写入内容到zip包,包装一个FileOutputStream,写入每个文件前,先调用putNextEntey(),然后用write()写入byte[]数据,最后调用closeEntry()结束这个文件的打包。