过去几天我一直在阅读Java中的流。在阅读了相当多的内容后,我开始明白,选择“流”这个名称是因为它与我们在“现实生活”中使用的词有相似之处,例如水。而且没有必要知道数据来自何处。如果我解释错了,请更正。
但我不明白这一点。当我在套接字上说getOutputStream
或getInputStream
时,我得到一个InputStream
,我可以链接到我喜欢的任何地方。但是不是InputStream / OutputStream抽象类吗?我不知道如何正确解释它但我不明白只是通过调用该方法的套接字连接有一个流/通道,其中字节/字符可以流动?什么是InputStream / OutputStream?溪流是一种抽象真实来源的方式吗?
我认为我理解了链接它们的各种方式,但我觉得我错过了这个概念的核心。
由于缺乏正确的解释方法,如果不好,我会删除问题。
感谢您的时间。
答案 0 :(得分:3)
当您调用getInputStream
时,套接字将返回InputStream
的某个具体子类的实例。通常你不用担心返回对象的确切类;因为它是InputStream
,所以你只需要这样做。 (子类甚至可以是套接字类的私有嵌套类。)
答案 1 :(得分:3)
InputStream
确实是一种抽象。在每种情况下,可以使用流概念的不同实现。但是流的用户不需要知道确切的实现是什么。
如果是Socket
,则实施为SocketInputStream
,其范围为FileInputStream
答案 2 :(得分:3)
InputStream
/ OutputStream
是抽象的。它们为您提供了一些用于读/写字节或字节组的基本API,而不会暴露实际的实现。我们以OutputStream
为例:
OutputStream
通过公共API接收一堆字节。实际上你并不知道(并关心)这些字节后发生了什么:它们是发送的。真正的实现可以:将它们附加到文件,忽略它们(在Apache Commons中NullOutputStream
),将它们保存在内存中或者......通过套接字发送。
当你致电Socket.getOutputStream()
时会发生这种情况:你得到OutputStream
的某些实现,只是不关心,它是依赖于实现的和具体的。当您向此流发送字节时,底层实现将使用TCP / IP或UDP推送它们。事实上,TCP / IP本身就是一种流协议,即使它在数据包/帧上运行。
InputStream
的情况类似 - 你从socket获得一些实现。当您向流请求少量字节时,基础InputStream
实现将向OS套接字请求相同数量的字节,可能是阻塞。但这是继承的真正乐趣:你不在乎!只需按照您想要的方式使用这些流,链接,缓冲等等。
答案 3 :(得分:3)
我认为这不是一个糟糕的问题。你很正确地从你那里抽象出数据来自何处的复杂性并使其统一。因此,您可以编写从文件或套接字读取的代码,并且该代码看起来几乎相同。这意味着您通常必须编写更少的代码。
当您从Socket获取InputStream时,您可以访问到达该套接字的任何数据。通常,在读取此流时,您提供一个字节数组并请求流为您填充它。它将读取尽可能多的数据或填充缓冲区。这取决于您对此字节数组中的数据执行的操作。
对于任何类型的Socket IO,虽然已经说过关于Streams的所有这些,但Java套接字API已经很老了,并且有一些非常好的替代品可以包装它并且更容易使用。我强烈推荐Netty使用,你可以忘记流,并专注于POJO以及如何编码和解码它们。