java.lang.Readable
字符的来源。
尝试读取字符到一个字符缓冲区,该字符缓冲区被当做一个字符仓库;引起字符缓冲区唯一的改变是put操作,字符缓冲区没有flipping或rewinding执行。接口返回添加到字符缓冲区的字符编码数目,如已经读取到字符源的末尾时则返回-1
java.lang.AutoCloseable
一种资源当它不再需要时必须关闭
关闭此资源,释放任何潜在资源。一些对象管理自动被调用该方法在try{}代码块声明的资源。
接口声明抛出Exception,建议具体实现抛出更为具体的Exceptions或者关闭成功完全不抛出Exception,建议实现该接口不抛出InterruptedException,该Exception与线程中断状态相互影响,运行时可能会发生不正常的行为。如果是因为一个被抑制的异常引起的,close就不会抛出。
注意,与java.io.Closeabe的close方法不同,该close方法是不要求幂等的,多次调用该方法可能会引起明显的副作用,所以实现该方法时建议使它的close是幂等的
java.io.Closeabe
一个来源or目标数据能够被关闭,close方法被调用,释放该对象拥有的资源,如打开文件。
关闭流并释放该流相关的系统资源,如果该流已经关闭了调用将不会生效
java.io.Reader
读取字符流的抽象类,子类必须实现read和close方法,多数子类会覆盖该类的方法为了额外功能或更加高效
int read(cbuf[], int offset, int len)
读取字符到数组的一部分,该方法将阻塞直到一些输入可用,一个IO错误或到达流的末尾
InputStreamReader
是一个字节流到字符流的桥:读取字节并使用指定的字符集解码到字符,字符集可以通过名称或明确指定或平台默认,每次调用一个read方法可能会引起一个or多个字节从字节输入流中被读取。
使字节有效转换成字符,多个字节可以从底层字节流的前面读取以满足当前读的操作,最高效的是,考虑在BufferedReader包装一个InputStreamReader
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
BufferedReader
从字符输入流中读取文本,缓存字符为了提供更有效阅读、数组和行。该字符缓冲区的大小可以指定,也可以使用默认,默认是足够大的对于大多数的需要。
通常,每一次读都会产生读相关的字符or字节流,故建议使用BufferedReader包装读的方式,eg:
BufferedReader in = new BufferedReader(new FileReader(“foo.in”));
从指定文件中缓存输入。不用缓存,每一个read 或readLine的调用都会引起字节从文件中读取,转换到字符,然后返回,这将是非常低效的。
程序可以使用一个合适的BufferedReader替换每个DataInputSteam为支持localized的文件输入
java.io.Serializable
类的序列化通过该类实现java.io.Serializable接口,未实现该接口的类将不会有任何其状态的序列化or反序列化,一个可序列化的所有子类型也是可序列化的。序列化接口没有定义方法or属性,他只标示可序列化的语义。
允许非序列化的子类进行序列化,该子类可假定用于保存和恢复父类中的public,protected,package字段的状态,该子类可假定只有当它继承的类有一个无参构造来初始化类的状态。如果不是这样,声明一个序列化类将得到错误,错误在运行时检测。
在反序列化期间,非序列化类的字段将使用public或protected 无参构造器初始化。可序列化的子类中必须有一个可访问的无参构造器,可序列化的子类的字段将从stream中恢复。
当遍历一个图形时,可能会遇到不支持可序列化接口的对象,则抛出NotSerializableException
并且识别非序列化对象的类。
类在序列化期间需要特殊处理和反序列化的过程必须使用如下确定签名的实现方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
writeObject写入特定类的对象状态,以便相应的readObject方法可以恢复它,保存对象的属性默认机制可以通过调用out.defaultWriteObject,这个方法不需要关注它自己使用状态属于父类or子类。通过写入独立的字段到 ObjectOutputStream来保存状态,可以使用原始类型支持的DataOutput。
readObject从stream中读取并且恢复类的属性,恢复对象的non-static和non-transient字段它可能调用in.defaultReadObject方法去调用默认机制,defaultReadObject使用在stream中信息去指定stream中保存对象的指定字段和根据当前对象的字段名称。当类已添加新的字段时就处理这种场景。 这个方法不需要关注它自己使用状态属于父类or子类。通过写入独立的字段到 ObjectOutputStream来保存状态,可以使用原始类型支持的DataOutput。
readObjectNoData在序列化流不列出给定类作为父类被反序列化时初始化特定类的对象的状态,这可能发生在,接收方使用一个不同于发送方版本的反序列化实例类,并且接收方继承类的版本不是由发送方版本继承。如果序列化流被篡改,因此readObjectNoData为初始化适当的反序列化对象or不完整的源流是有用的。
序列化类需要指定要使用的可替代对象时,写一个对象到流应该实现这一特殊的方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
writeReplace如果该方法存在并且能从被序列化对象的类中方法定义中可访问时,被序列化过程调用,
因此,该方法可以有private、protected和package-private访问
需要指定要使用的可替代对象时,从流中读取类的实例应该实现这一特殊的方法:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
readResolve与writeReplace有着相同的调用和访问规则
序列化过程使用每个序列化类的版本号关联(serialVersionUID)这是用在反序列化过程中来验证发送发和接受方有一个序列化对象被加载,这是关于对象序列化的兼容。如果接受方加载对象的类有一个不同与发送方 serialVersionUID,则在反序列化过程的结果产生InvalidClassException。一个可序列化的类能够明确声明一个static,final,long的 serialVersionUID字段。
如果一个序列化的类没有明确声明一个 serialVersionUID,则序列化过程会为这个类计算一个默认的 serialVersionUID值,描述在java对象序列化规范中。然而,强烈推荐所有序列化类都明确声明一个serialVersionUID值,因为默认的 serialVersionUID计算是类的细节,可能取决于编译器所实现不同高度敏感的,从而导致反序列化过程中产生未预期的InvalidClassException。因此,为了保证在不同编译器有一致的serialVersionUID值,则序列化的类必须声明一个serialVersionUID值。同样建议serialVersionUID声明尽可能使用private,因为这样的声明只适应于立即类—serialVersionUID作为继承成员是没有用的。Array类不能声明一个明确的serialVersionUID值,故它总是有一个默认计算值,但Array class是不要求匹配serialVersionUID值。