、SequenceInputStream源码——可以顺序读取多个输入Stream的装饰器类SequenceInputStream.class 的UML关系图如下所示SequenceInputStream.class的源码如下所示package java.io; import java.io.InputStream; import java.util.Enumeration; import java.util.Vector; public class SequenceInputStream extends InputStream { //顺序序列化装载多个被装饰输入Stream的集合一般是Vector实例 Enumeration? extends InputStream e; InputStream in;//顺序序列化装载多个被装饰输入Stream的集合中当前正在被SequenceInputStream 对象使用的被装饰的输入Stream //构造函数传入一个顺序序列化装载多个被装饰输入Stream的集合 public SequenceInputStream(Enumeration? extends InputStream e) { this.e e; try { nextStream(); } catch (IOException ex) { // This should never happen throw new Error(panic); } } //构造函数可以将2个被装饰的输入Stream放入到集合中 public SequenceInputStream(InputStream s1, InputStream s2) { VectorInputStream v new Vector(2); v.addElement(s1); v.addElement(s2); e v.elements(); try { nextStream(); } catch (IOException ex) { // This should never happen throw new Error(panic); } } //获取集合中下一个被装饰的输入Stream final void nextStream() throws IOException { if (in ! null) { in.close();//先关闭当前被装饰的输入Stream } if (e.hasMoreElements()) {//如果集合中还有被装饰的输入Stream in (InputStream) e.nextElement();//获取集合中下一个被装饰的输入Stream if (in null) throw new NullPointerException();//如果集合中下一个被装饰的输入Stream为null抛出一个NullPointerException } else in null;//如果集合中没有了被装饰的输入Stream将当前正在使用的被装饰的输入Stream置为null } //判断当前正在使用的被装饰的输入Stream是否还有可以读取的字节数据 public int available() throws IOException { if (in null) { return 0; // no way to signal EOF from available() } return in.available(); } //从SequenceInputStream 对象的集合该集合放着多个被装饰的输入Stream中读取1个字节 public int read() throws IOException { while (in ! null) {//如果in!null则说明当前这个SequenceInputStream 对象的集合中还有被装饰的输入Stream没有关闭 int c in.read();//从当前正在使用的被装饰的被装饰输入Stream中读取1个字节 if (c ! -1) {//c ! -1说明从当前正在使用的被装饰输入Stream中读取到了字节 return c;//返回读取到的这个字节 } nextStream();//如果c-1说明当前正在使用的被装饰输入Stream中字节byte数据已经读完获取SequenceInputStream 对象的集合中下一个被装饰的输入Stream } return -1;//如果SequenceInputStream 对象的集合中所有被装饰的输入Stream中的字节byte数据都已经读完返回-1 } //从SequenceInputStream 对象的集合该集合放着多个被装饰的输入Stream中读取len个字节放入到byte[]数组b的[off,offlen)左闭右开不包括offlen索引位置 public int read(byte b[], int off, int len) throws IOException { if (in null) {//如果innull则说明当前这个SequenceInputStream 对象的集合中所有被装饰的输入Stream都已经关闭 return -1; } else if (b null) { throw new NullPointerException();//如果byte[]数组bnull抛出一个NullPointerException } else if (off 0 || len 0 || len b.length - off) {//相当于off len b.length源码中这样写代码的好处我没看出来 throw new IndexOutOfBoundsException(); } else if (len 0) { return 0;//要从SequenceInputStream 对象的集合该集合放着至少2个被装饰的输入Stream中读取的len个字节0时返回0 } do { int n in.read(b, off, len);//从当前正在使用的被装饰的输入Stream中读取len个字节放入到byte[]数组b的[off,offlen)左闭右开不包括offlen索引位置 if (n 0) { return n;//只要能从当前正在使用的被装饰的输入Stream中读取到字节则返回读取的数量 } nextStream();//此时n-1说明当前正在使用的被装饰的输入Stream中字节byte数据已经读完获取SequenceInputStream 对象的集合中下一个被装饰的输入Stream } while (in ! null);//SequenceInputStream 对象的集合中下一个被装饰的输入Stream为null时跳出循环返回-1 return -1; } //顺序关闭SequenceInputStream 对象的集合中所有被装饰的输入Stream public void close() throws IOException { do { nextStream(); } while (in ! null); } }1.1、SequenceInputStream的read()函数和nextStream()函数package java.io; import java.io.InputStream; import java.util.Enumeration; import java.util.Vector; public class SequenceInputStream extends InputStream { ...省略部分代码... //顺序序列化存储多个被装饰的输入Stream的集合一般是Vector实例 Enumeration? extends InputStream e; InputStream in;//顺序序列化装载多个被装饰输入Stream的集合中当前正在被SequenceInputStream 对象使用的被装饰的输入Stream //获取集合中下一个被装饰的输入Stream final void nextStream() throws IOException { if (in ! null) { in.close();//先关闭当前被装饰的输入Stream } if (e.hasMoreElements()) {//如果集合中还有被装饰的输入Stream in (InputStream) e.nextElement();//获取集合中下一个被装饰的输入Stream if (in null) throw new NullPointerException();//如果集合中下一个被装饰的输入Stream为null抛出一个NullPointerException } else in null;//如果集合中没有了被装饰的输入Stream将当前正在使用的被装饰的输入Stream置为null } //从SequenceInputStream 对象的集合该集合放着多个被装饰的输入Stream中读取1个字节 public int read() throws IOException { while (in ! null) {//如果in!null则说明当前这个SequenceInputStream 对象的集合中还有被装饰的输入Stream没有关闭 int c in.read();//从当前正在使用的被装饰的被装饰输入Stream中读取1个字节 if (c ! -1) {//c ! -1说明从当前正在使用的被装饰输入Stream中读取到了字节 return c;//返回读取到的这个字节 } nextStream();//如果c-1说明当前正在使用的被装饰输入Stream中字节byte数据已经读完获取SequenceInputStream 对象的集合中下一个被装饰的输入Stream } return -1;//如果SequenceInputStream 对象的集合中所有被装饰的输入Stream中的字节byte数据都已经读完返回-1 } ...省略部分代码... }如果使用者用的是2个被装饰的输入Stream此处为FileInputStream构造的SequenceInputStream的对象如下所示伪代码is1 new FileInputStream(D:\\data1.txt); is2 new FileInputStream(D:\\data2.txt); sequenceInputStream new SequenceInputStream(is1, is2);那么SequenceInputStream对象中Vector集合的容量是2如果此时执行SequenceInputStream.class::read()函数。//伪代码 int readByte -1; while ((readByte sequenceInputStream.read()) ! -1) { System.out.print((char) readByte); }过程如下假设2个被装饰的输入Stream此处为FileInputStream中的字节数据如下①、先执行第1个被装饰的输入Stream也是Vector集合的第1个元素的read()函数直到该函数返回-1如下所示②、关闭第1个被装饰的输入Stream也是Vector集合的第1个元素再执行第2个被装饰的输入Stream也是Vector集合的第2个元素的read()函数直到该函数返回-1如下所示1.1.1、使用举例下面这个例子就恰当的使用SequenceInputStream的read()函数我的windows操作系统的D盘根目录下有2个txt文件一个是data1.txt另一个是data2.txt文件这2个文件中总共有30个字节如下所示使用者可以用一个SequenceInputStream对象装饰2个被装饰的输入Stream此处为FileInputStream如下代码所示package com.chelong.StreamAndReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; public class SequenceInputStreamTest { public static void main(String[] args) { InputStream is1 null; InputStream is2 null; SequenceInputStream sequenceInputStream null; try { is1 new FileInputStream(D:\\data1.txt); is2 new FileInputStream(D:\\data2.txt); sequenceInputStream new SequenceInputStream(is1, is2); int readByte -1; while ((readByte sequenceInputStream.read()) ! -1) { System.out.print((char) readByte); } } catch (IOException e) { e.printStackTrace(); } finally { //此处省略关闭所有的Stream的代码 } } }程序运行结果如下所示1.2、SequenceInputStream的read(byte b[], int off, int len)函数和nextStream()函数package java.io; import java.io.InputStream; import java.util.Enumeration; import java.util.Vector; public class SequenceInputStream extends InputStream { ...省略部分代码... //顺序序列化装载多个被装饰输入Stream的集合一般是Vector实例 Enumeration? extends InputStream e; InputStream in;//顺序序列化装载多个被装饰输入Stream的集合中当前正在被SequenceInputStream 对象使用的被装饰的输入Stream //获取集合中下一个被装饰的输入Stream final void nextStream() throws IOException { if (in ! null) { in.close();//先关闭当前被装饰的输入Stream } if (e.hasMoreElements()) {//如果集合中还有被装饰的输入Stream in (InputStream) e.nextElement();//获取集合中下一个被装饰的输入Stream if (in null) throw new NullPointerException();//如果集合中下一个被装饰的输入Stream为null抛出一个NullPointerException } else in null;//如果集合中没有了被装饰的输入Stream将当前正在使用的被装饰的输入Stream置为null } //从SequenceInputStream 对象的集合该集合放着多个被装饰的输入Stream中读取len个字节放入到byte[]数组b的[off,offlen)左闭右开不包括offlen索引位置 public int read(byte b[], int off, int len) throws IOException { if (in null) {//如果innull则说明当前这个SequenceInputStream 对象的集合中所有被装饰的输入Stream都已经关闭 return -1; } else if (b null) { throw new NullPointerException();//如果byte[]数组bnull抛出一个NullPointerException } else if (off 0 || len 0 || len b.length - off) {//相当于off len b.length源码中这样写代码的好处我没看出来 throw new IndexOutOfBoundsException(); } else if (len 0) { return 0;//要从SequenceInputStream 对象的集合该集合放着至少2个被装饰的输入Stream中读取的len个字节0时返回0 } do { int n in.read(b, off, len);//从当前正在使用的被装饰的输入Stream中读取len个字节放入到byte[]数组b的[off,offlen)左闭右开不包括offlen索引位置 if (n 0) { return n;//只要能从当前正在使用的被装饰的输入Stream中读取到字节则返回读取的数量 } nextStream();//此时n-1说明当前正在使用的被装饰的输入Stream中字节byte数据已经读完获取SequenceInputStream 对象的集合中下一个被装饰的输入Stream } while (in ! null);//SequenceInputStream 对象的集合中下一个被装饰的输入Stream为null时跳出循环返回-1 return -1; } ...省略部分代码... }如果使用者用的是2个被装饰的输入Stream此处为FileInputStream构造的SequenceInputStream的对象如下所示伪代码is1 new FileInputStream(D:\\data1.txt); is2 new FileInputStream(D:\\data2.txt); sequenceInputStream new SequenceInputStream(is1, is2);那么SequenceInputStream对象中Vector集合的容量是2并且假设这2个被装饰的输入Stream此处为FileInputStream中的字节数据如下如果此时执行SequenceInputStream.class::read()函数。接下来使用SequenceInputStream对象读取字节数据到使用者创建的byte[]数组如果使用者创建的字节数组byte[]的长度第1个被装饰的输入Stream中的所有字节个数比如使用者创建的byte[]数组的长度为12如下所示伪代码int readByte -1; byte[] buff new byte[12]; while ((readByte sequenceInputStream.read(buff, 0, buff.length)) ! -1) { for (int i 0; i readByte; i) { System.out.print((char) buff[i]); } }整个执行过程如下①、第1次进入read()函数②、第2次进入read()函数重点是当前正在使用的被装饰的输入Stream中的字节数据已经读取完了时再次读取会返回-1不会返回0③、第3次进入read()函数④、第4次进入read()函数重点是当前正在使用的被装饰的输入Stream中的字节数据已经读取完了时再次读取会返回-1不会返回0最终使用者创建的byte[]数组中的字节byte数据如下所示1.2.1、使用举例下面这个例子就恰当的使用SequenceInputStream的read()函数我的windows操作系统的D盘根目录下有2个txt文件一个是data1.txt另一个是data2.txt文件这2个文件中总共有30个字节如下所示使用者可以用一个SequenceInputStream对象装饰2个被装饰的输入Stream此处为FileInputStream如下代码所示package com.chelong.StreamAndReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; import java.util.Vector; public class SequenceInputStreamTest { public static void main(String[] args) { InputStream is1 null; InputStream is2 null; SequenceInputStream sequenceInputStream null; try { is1 new FileInputStream(D:\\data1.txt); is2 new FileInputStream(D:\\data2.txt); VectorInputStream vector new VectorInputStream(); vector.addElement(is1); vector.addElement(is2); sequenceInputStream new SequenceInputStream(vector.elements()); int readByte -1; byte[] buff new byte[12]; while ((readByte sequenceInputStream.read(buff, 0, buff.length)) ! -1) { for (int i 0; i readByte; i) { System.out.print((char) buff[i]); } } System.out.println(); System.out.println(最终留在byte[]数组buff中的字节); for (byte b : buff) { System.out.print((char) b); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (is1 ! null) is1.close(); if (is2 ! null) is1.close(); if (sequenceInputStream ! null) sequenceInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }程序运行结果如下所示二、Vector.class的一些函数说明Vector 与 ArrayList 一样也是通过数组实现的不同的是它支持线程的同步即某一时刻只有一个线程能够写 Vector避免多线程同时写而引起的不一致性但实现同步需要很高的花费因此访问它比访问 ArrayList慢。Vector的UML图如下所示2.1、构造函数函数名函数说明public Vector()此构造函数创建的Vector中Object[]数组的初始长度为10capacityIncrement0capacityIncrement表示扩容时Object[]数组增加的长度如果等于0的话当Object[]数组需要扩容时新的数组长度2*旧数组的长度但是新的数组长度最大为2^31-8public Vector(int initialCapacity)此构造函数创建的Vector中Object[]数组的初始长度为initialCapacitycapacityIncrement0capacityIncrement表示扩容时Object[]数组增加的长度如果等于0的话当Object[]数组需要扩容时新的数组长度2*旧数组的长度但是新的数组长度最大为2^31-8public Vector(int initialCapacity, int capacityIncrement)此构造函数创建的Vector中Object[]数组的初始长度为initialCapacitycapacityIncrementcapacityIncrementcapacityIncrement表示扩容时Object[]数组增加的长度如果等于0的话当Object[]数组需要扩容时新的数组长度2*旧数组的长度但是新的数组长度最大为2^31-8public Vector(Collection? extends E c)此构造函数创建的Vector中Object[]数组的初始长度为传入集合Collection? extends E c的长度capacityIncrement0capacityIncrement表示扩容时Object[]数组增加的长度如果等于0的话当Object[]数组需要扩容时新的数组长度2*旧数组的长度但是新的数组长度最大为2^31-82.2、常用函数函数名函数说明boolean add(E o)此函数将指定的元素追加到此Vector的末尾该函数与addElement()函数的区别是该()函数是List.interface接口规定的函数addElement()函数是Vector自己实现的接口中没有规定addElement()函数void add(int index, E element)此函数将指定的元素插入此Vector中的指定索引位置boolean addAll(Collection? extends E c)此函数将指定Collection中的所有元素追加到此Vector的末尾boolean addAll(int index, Collection? extends E c)此函数将指定Collection中的所有元素插入到此Vector中的指定索引位置void addElement(E obj)此函数将指定的元素追加到此Vector的末尾这个函数与add()函数的区别是add()函数是List.interface接口规定的函数这个函数是Vector自己实现的接口中没有规定该函数int capacity()此函数返回此Vector的当前容量void clear()此函数从此Vector中删除所有元素Object clone()此函数返回此Vector的克隆对象boolean contains(Object elem)如果此Vector包含指定的元素则此函数返回trueboolean containsAll(Collection? c)如果此Vector包含指定Collection中的所有元素则此函数返回truevoid copyInto(Object[] anArray)此方法将此向量的组件复制到指定的数组中E elementAt(int index)此函数返回Vector指定索引处的元素Enumeration elements()此函数返回此Vector中所包含的所有元素的枚举。void ensureCapacity(int minCapacity)此函数可增加此Vector的容量以确保它至少可以保存最小容量元素个数boolean equals(Object o)此函数将指定的Object与此Vector进行比较以获得相等性E firstElement()返回此Vector的第一个元素位于Object[]数组索引 0 处的元素E get(int index)返回Vector中指定索引位置的元素int indexOf(Object elem)搜索给定参数的第一个匹配项使用 equals ()函数测试相等性int indexOf(Object elem, int index)搜索给定参数的第一个匹配项从 index 处开始搜索并使用 equals()函数测试其相等性void insertElementAt(E obj, int index)将指定对象作为此Vector中的元素插入到指定的 索引位置boolean isEmpty()测试此Vector中的是否不包含任何元素E lastElement()返回此Vector的最后一个元素位于Object[]数组索引 Object[].length-1 处的元素int lastIndexOf(Object elem)返回指定的对象在此Vector中最后一个匹配项的索引int lastIndexOf(Object elem, int index)从指定的索引处开始向后搜索指定的对象并返回搜索到的最后一个索引E remove(int index)移除此Vector中指定索引位置的元素boolean remove(Object o)移除此Vector中指定元素的第一个匹配项如果此Vector不包含该元素则所有元素保持不变并返回falseboolean removeAll(Collection? c)从此Vector中移除包含在指定 Collection 中的所有元素void removeAllElements()从此Vector中移除全部元素并设置elementCount0该变量表示此Vector对象中有效元素的数量Object[]数组的长度不变。void removeElementAt(int index)删除指定索引处的元素protected void removeRange(int fromIndex, int toIndex)从此 Vector 中移除索引位于 [fromIndex, toIndex)左闭右开之间的所有元素boolean retainAll(Collection? c)如果此Vector中包含指定 Collection 中的所有元素此函数返回trueE set(int index, E element)用指定的元素替换此Vector中指定索引处的元素void setElementAt(E obj, int index)将此Vector指定 索引处的元素设置为指定的另一个元素void setSize(int newSize)设置此Vector的大小int size()返回此Vector中的元素数List subList(int fromIndex, int toIndex)返回此 Vector的子集该子集的元素范围为 [fromIndex, toIndex)左闭右开索引位置的所有元素Object[] toArray()返回一个Object[]数组包含此Vector中以正确顺序存放的所有元素String toString()返回此Vector的字符串表示形式其中包含每个元素的 String 表示形式