InputStreamReader 的 equals() 和 hashCode() 继承自 Object,仅基于对象引用和内存地址,不比较内容或状态;这是合理设计,因其封装可变资源,无法定义可靠的逻辑相等。

InputStreamReader 是 Java I/O 中的桥接类,它把字节流(InputStream)按指定字符集解码为字符流(Reader)。它本身不重写 equals() 和 hashCode() 方法,因此直接继承自 Object 类的默认实现。
这意味着:
-
equals()判断的是引用相等:只有两个变量指向同一个InputStreamReader实例时,equals()才返回true; -
hashCode()返回的是该对象的内存地址哈希值(由 JVM 本地方法生成),与内部状态(如底层流、编码、缓冲区内容等)完全无关。
为什么 InputStreamReader 不重写 equals 和 hashCode?
因为 InputStreamReader 的语义本质上是不可比较的资源型对象:
- 它封装了可变状态(如已读字节位置、解码器状态、缓冲区等);
- 即使两个
InputStreamReader包装了相同的InputStream并使用相同Charset,只要不是同一个实例,它们的读取进度、缓冲区内容、错误恢复状态都可能不同; - 没有业务上“逻辑相等”的合理定义——你无法可靠地判断“两个 InputStreamReader 是否代表相同的字符序列起点”,尤其在流已部分读取后。
所以,Java 设计者有意不重写这两个方法,避免误导使用者以为可以安全用于 HashMap 键或 HashSet 元素。
立即学习“Java免费学习笔记(深入)”;
实际影响举例
InputStream is1 = new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8));
InputStream is2 = new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8));
InputStreamReader r1 = new InputStreamReader(is1, StandardCharsets.UTF_8);
InputStreamReader r2 = new InputStreamReader(is2, StandardCharsets.UTF_8);
System.out.println(r1.equals(r2)); // false(引用不同)
System.out.println(r1.hashCode() == r2.hashCode()); // 几乎总是 false(不同对象,不同地址哈希)即使 is1 和 is2 内容一致,r1 和 r2 仍是独立对象,equals() 和 hashCode() 不做内容比对。
如果你真需要“可比较”的字符流抽象?
应自行封装并定义逻辑相等规则,例如:
- 比较底层
InputStream的内容是否相同(需重置/重复读取); - 或基于流源标识(如文件路径 + 编码)构造不可变描述符(如
new StreamDescriptor("data.txt", UTF_8)),再对该描述符重写equals/hashCode。
但注意:InputStreamReader 本身不适合做键或去重元素。
总结关键点
-
InputStreamReader.equals()→ 只认“是不是同一个对象”; -
InputStreamReader.hashCode()→ 基于对象身份,非内容; - 不重写是合理设计,不是疏漏;
- 把它放进
HashMap当 key 或HashSet当元素,会导致行为不符合预期(比如重复插入、查不到); - 需要逻辑相等?请封装、抽象、自定义,不要依赖
InputStreamReader自身。


















