【问题标题】:Questions on Java's I/O Classes关于 Java 的 I/O 类的问题
【发布时间】:2015-10-01 09:07:08
【问题描述】:

我正在阅读有关 java 网络(客户端/服务器)的本教程,我对一些我不明白的事情有疑问。

https://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html

我经常看到这种情况

BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

BufferedReader inputStream = new BufferedReader(new FileReader("xanadu.txt"));
PrintWriter outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));

我知道 BufferReader 的构造函数是

BufferedReader(Reader in)

1) 我还知道,由于 InputStreamReader 是由 Reader 类继承的,因此您可以通过 BufferedReader 构造函数传递它。但我的问题是为什么我们需要 InputStreamReader?是不是因为 InputStreamReader 可以保存一个输入流(根据它在 API 中的构造函数)

编辑:我犯了错误,请忽略这个

2) 现在对于下一部分,inputStream 和 outputStream(根据 API)是从 Object 类继承的。这两个类如何分别分配为 BufferedReader 和 PrintWriter。这是因为它们都被对象类继承,还是它们的另一个原因?因为如果是这种情况,那么任何人都将如何知道您可以将什么分配为类,就好像一切都应该由 Objects 类继承一样。

3) 最后但并非最不重要的一点是,这里还有一个关于 BufferedReader 和 PrintWriter 的问题

BufferedReader inputStream = new BufferedReader(new FileReader("xanadu.txt"));
PrintWriter outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));

为什么这两个类,选择通过 FileReader 和 FileWriter 类的引用?

我想我想了解更多关于为什么选择这些特定课程的信息。

提前致谢!

【问题讨论】:

  • 您没有显示 inputStream 和 outputStream 的实际类型。如果它们真的是 InputStream 和 OutputStream,不,那个赋值是行不通的。
  • 你的问题揭示了一个误解,在考虑继承问题之前你应该澄清这个误解:Java 中的二进制与文本。您可能想阅读this
  • @pvg 你的权利,我把那部分搞砸了,谢谢
  • @fge 有些说得通,谢谢

标签: java inheritance java-io


【解决方案1】:

好的,原因很简单

这是装饰器设计模式。 你拿了一个基本的对象,并继续在它上面添加所需的装饰。 示例:有 2 种配料的披萨(我现在饿了)

您这样做是因为它减少了所需的不同类的数量(InputStreamReader * Buffered/UnBuffered * bla bla bla 导致许多不同的组合,所以如果我们为每个组合有一个子类,它将是 100 多个流类,我们会混淆,所以我们简单地装饰它(所有类型都有相同的接口,我们在构造函数中相互传递)

如果仍有疑问,请使用谷歌装饰器模式了解详情

【讨论】:

    【解决方案2】:

    1) 要构造BufferedReader,您需要一个Reader 参数。 System.in 不是 Reader。 Java IO 难题的每一部分只做一件事:InputStreamReaderInputStream 中获取Reader,然后BufferedReader 缓冲Reader

    2) 他们不能,正是因为#1。首先将InputStream 包装在ReaderWriter 包装器中,然后您可以做其他事情。

    3) 因为它们正在读取/写入文件,而不是流。 (编辑:正如 pvg 在 cmets 中提到的那样,inputStream = new BufferedReader(...)outputStream = new PrintWriter(...) 是非常令人困惑的变量名。)


    基本上,它就像一个制造商。你有System.in,这是一个InputStream。这意味着他正在给你简单的字节。你不想要纯字节;您希望获得字符(即通过某些字符编码解析的字节,例如 UTF-8)。但是InputStream 不知道该怎么做。

    输入InputStreamReader。正如每个Reader,他知道如何给你角色。特别是InputStreamReader 知道如何从InputStream 获取字节并将其作为字符传递。所以你把他排在System.in前面,这样你就不用和他打交道了。

    但您不想一次只获得一个角色。你想要更多。您希望能够一次阅读整行!你想要……一个缓冲区!输入BufferedReader:他是站在另一个Reader 前面的人,收集每个角色并把它藏起来,直到你要一些。

    要确切了解发生了什么,您需要了解基于字节的 IO 和基于文本的 IO 之间的关键区别,并研究每个类的构造函数以确切了解它包装了什么样的东西(尽管名称是很好的提示)。

    【讨论】:

    • 为什么这个答案被否决了?这正是OP所要求的!另外,点赞,+1。
    • 同意。好答案。我也 +1。
    • @Amadan 这个答案很棒,我真的很感激。我确实读过一篇关于 java I/O 的小文章,但我认为你填补了空白。我认为我仍然迷失的唯一部分是这些信息也保存在哪里?您提到: Bytes -> char -> buffered = System.in 被传递到 InputStream 被传递到 InputStreamReader 被传递到 BufferedReader。所以流最终是原始的,然后转换然后缓冲,但是数据保存在哪里,是否保存到私有类变量?因为我知道当你传入一个构造函数时,对象必须被保存到某个东西,对吧?
    • 不必,但通常是。但是,这不再是您的问题,因为这些类来自标准库;您可以将它们视为黑匣子。你需要知道的是,如果你用BufferedReader 包裹一些东西,你突然就可以使用readLine,例如。但是,是的,如果你好奇的话,somewhere deep downBufferedReader 记得他从哪个Reader 得到他的东西,并且还有一个记事本(或者更确切地说是一个char[])来记下他说的话。跨度>
    • 非常感谢您发布的链接。谢谢。我一直在寻找这样的东西!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多