NIO — Channel 与 Buffer
📋 本文节选自《NIO 面试题》,返回 查看全部章节
8. IO流的分类
![ ][nbsp]
按照读写的单位大小来分:
字符流 :以字符为单位,每次次读入或读出是16位数据。其只能读取字符类型数据。 (Java代码接收数据为一般为 char数组,也可以是别的 )
字节流:以字节为单位,每次次读入或读出是8位数据。可以读任何类型数据,图片、文件、音乐视频等。 (Java代码接收数据只能为 byte数组 )
按照实际IO操作来分:
输出流:从内存读出到文件。只能进行写操作。
输入流:从文件读入到内存。只能进行读操作。
注意:输出流可以帮助我们创建文件,而输入流不会。
按照读写时是否直接与硬盘,内存等节点连接分:
节点流:直接与数据源相连,读入或读出。
处理流:也叫包装流,是对一个对于已存在的流的连接进行封装,通过所封装的流的功能调用实现数据读写。如添加个Buffering缓冲区。(意思就是有个缓存区,等于软件和mysql中的redis)
注意:为什么要有处理流?主要作用是在读入或写出时,对数据进行缓存,以减少I/O的次数,以便下次更好更快的读写文件,才有了处理流。
9. 什么是内核空间
我们的应用程序是不能直接访问硬盘的,我们程序没有权限直接访问,但是操作系统(Windows、Linux…)会给我们一部分权限较高的内存空间,他叫内核空间,和我们的实际硬盘空间是有区别的
![ ][nbsp 1]
10. 五种IO模型
注意:我这里的用户空间就是应用程序空间
1. 阻塞BIO(blocking I/O)
A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候不做其他的事情,十分专心。只有鱼上钩的时,才结束掉等的动作,把鱼钓上来。
在内核将数据准备好之前,系统调用会一直等待所有的套接字,默认的是阻塞方式。
![ ][nbsp 2]
2. 非阻塞NIO(noblocking I/O)
B也在河边钓鱼,但是B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中,B也在做其他的事情(一会看看书,一会读读报纸,一会又去看其他人的钓鱼等),但B在做这些事情的时候,每隔一个固定的时间检查鱼是否上钩。一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。 B在检查鱼竿是否有鱼,是一个轮询的过程。![ ][nbsp 3]
3. 异步AIO(asynchronous I/O)
C也想钓鱼,但C有事情,于是他雇来了D、E、F,让他们帮他等待鱼上钩,一旦有鱼上钩,就打电话给C,C就会将鱼钓上去。
![ ][nbsp 4]
当应用程序请求数据时,内核一方面去取数据报内容返回,另一方面将程序控制权还给应用进程,应用进程继续处理其他事情,是一种非阻塞的状态。
4. 信号驱动IO(signal blocking I/O)
G也在河边钓鱼,但与A、B、C不同的是,G比较聪明,他给鱼竿上挂一个铃铛,当有鱼上钩的时候,这个铃铛就会被碰响,G就会将鱼钓上来。
![ ][nbsp 5]
信号驱动IO模型,应用进程告诉内核:当数据报准备好的时候,给我发送一个信号,对SIGIO信号进行捕捉,并且调用我的信号处理函数来获取数据报。
5. IO多路转接(I/O multiplexing)
H同样也在河边钓鱼,但是H生活水平比较好,H拿了很多的鱼竿,一次性有很多鱼竿在等,H不断的查看每个鱼竿是否有鱼上钩。增加了效率,减少了等待的时间。
![ ][nbsp 6]
IO多路转接是多了一个select函数,select函数有一个参数是文件描述符集合,对这些文件描述符进行循环监听,当某个文件描述符就绪时,就对这个文件描述符进行处理。
IO多路转接是属于阻塞IO,但可以对多个文件描述符进行阻塞监听,所以效率较阻塞IO的高。
11. 什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别
Bit最小的二进制单位 ,是计算机的操作部分取值0或者1
Byte是计算机中存储数据的单元,是一个8位的二进制数,(计算机内部,一个字节可表示一个英文字母,两个字节可表示一个汉字。) 取值(-128-127)
Char是用户的可读写的最小单位,他只是抽象意义上的一个符号。如‘5’,‘中’,‘¥’ 等等等等。在java里面由16位bit组成Char 取值 (0-65535)
Bit 是最小单位 计算机他只能认识0或者1
Byte是10个字节 是给计算机看的
字符 是看到的东西 一个字符=二个字节
12. 什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作
对象序列化,将对象以二进制的形式保存在硬盘上
反序列化;将二进制的文件转化为对象读取
实现serializable接口,不想让字段放在硬盘上就加transient
13. 在实现序列化接口是时候一般要生成一个serialVersionUID字段,它叫做什么,一般有什么用
如果用户没有自己声明一个serialVersionUID,接口会默认生成一个serialVersionUID
但是强烈建议用户自定义一个serialVersionUID,因为默认的serialVersinUID对于class的细节非常敏感,反序列化时可能会导致InvalidClassException这个异常。
(比如说先进行序列化,然后在反序列化之前修改了类,那么就会报错。因为修改了类,对应的SerialversionUID也变化了,而序列化和反序列化就是通过对比其SerialversionUID来进行的,一旦SerialversionUID不匹配,反序列化就无法成功。
14. 怎么生成SerialversionUID
可序列化类可以通过声明名为 “serialVersionUID” 的字段(该字段必须是静态 (static)、最终(final) 的 long 型字段)显式声明其自己的 serialVersionUID
两种显示的生成方式(当你一个类实现了Serializable接口,如果没有显示的定义serialVersionUID,Eclipse会提供这个提示功能告诉你去定义 。在Eclipse中点击类中warning的图标一下,Eclipse就会自动给定两种生成的方式。