00:01
缓冲区buffer。缓冲器buffer呢?前面我们举了一个例子,现在呢我们再系统的说一下。缓冲区buffer本质是一个可读写的内存块,可以理解成是一个容器对象。也就是说,你可以把它理解成是一个容器对象,这个对象里面呢,它含有一个数组,该对象提供了一组方法,可以轻松的使用内存块缓冲区。对对象内置的一些机制能够跟踪和记录缓冲区的状态变化。那么这些机制是怎么样子呢?待会儿我们可以看它,这里面最重要的有四个标志位。这四个标志位分别代表什么含义?一会我们就会说这个事情的,China呢,提供了下面这个图,可以看到China提供了从文件网络读取数据的通道,比如说我们这个China呢,可以跟我们的数据源进行一个交互,能够跟踪和记录缓冲区的状态变化,对不对?然后呢,但是读写数据必须经过buffer,也就是说我们这个程序呢,不能够直接通这个。
01:09
China来读取,而要通过中间的缓冲区。这个示意图呢,就把他们之间的关系描述清楚了。下面呢,我们再来这看一下怎么理解这句话,他说China可以理解成是一个容器,对象含一个数组,我们来看这句话怎么理解哈,来打开我们的代码,前面我们写了一个basic buffer,我们看一下。我们定到这个buffer里面去。进到这里面去过后呢,我们可以看到buffer的它最顶级,顶级的这个buffer是一个抽象类,里面呢含有四个属性mark。Position,这个position呢,就实际上是标识的是我们当前这一个数组的。所以limit呢,代表我对这个数组最大可以读取多少个,或者是写入多少个。
02:05
Capacity就是它的容量,这四个属性呢,我们后面马上就会说到啊,待会我们通过debug来看一下他们这四个参数的变化,另外一个呢,同学们可以看到这个int哈。In的buffer,大家有发现在这个buffer来说呢。我们看一下buffer来说,下面它有。几个子类,Int float char double short和,那那我们我们来看看这这里面有一个什么东西,特别重要的是哪一个呢?就它大家有没有发现在英特buffer里面呢,有一个这样的数组。HB。啊,这是一个int数组,在我们的float buffer里面呢,也有一个数组,Float数组在char呢,有一个char数组,在我们的double buffer里面有double数组,以此类推。我就不一个看到,也就是说我们将来的这些个buffer对象,其实它真正的数据就是你放的真正的数据就是存放在他的这一个数组属性里边的。
03:07
明白了吧?然后我们接着继续往下看吧,继续往下看。巴布类及其子类。在NIO里边呢,Buffer是一个顶级的负类,是一个抽象类,对同学们大家,呃,刚才大家已经看到了,Buffer下面子类最常用这么七个都有。但是有一点哈,Booing没有相应的缓冲区,没有冲对象啊,Bet,你看bet bet buffer short buffer这个bitt buffer呢,就是存储字节数组,把字节数据,把字节数据存放,带缓冲区,这个呢,就short这char int no double和float,也就是说你将来要去读取怎样的数据,你就选用相应的。Buffer对象就可以了,创建相应的buffer对象就可以了。其实大家也可以想象到,在我们网络编程中,其实不管是short char还是什么,最终呢,都是按字节来进行传送的,对不对?所以说这里面用的最多的显然应该是bad buffer。
04:11
啊,那这个每一个buff下面呢,还有相应的子类。我们看一下,你比如说在int buffer里面呢,还有这样的子类,看direct啊,Direct in buffer,还有by buffer as in buffer,那就是我们的这一个bad buffer呢,和这个in buffer的互转的一些方法,你在下面float也是一样的看,基本上都是一个对应的关系,你看这一个help in buffer,这有个help float buffer等等。这是它的相应的子类,那接着呢,我们再来看一个刚才没有解决的问题,就是说我们这个buff本,它的这几个标志位分别代表什么buffer类呢?定义了所有缓冲区都具有的四个属性,因为它是负类吗?所以说其他的子类呢,都会继承这四个重要的属性,这四个属性是用来提供关于其所包含的数据元素的信息。
05:10
好,我们来看一下第一个capacity,这个capacity thirty呢,简单的讲就是这个容量它是不可变的。对,也就是说在缓冲区创建的时候被设定并且不可以改变,你比如说我在前面创建了一个int buffer,那么。我设置的是五,它的容量就是五,也就是说我们这一个buffer呢,最多可以存放五个int数据,Limit就不一样了,这个limit呢,在整个运行的过程中它是变化的,它表示缓冲区的当前终点,不能对缓冲区超过极限的位置进行读写,且极限是可以修改的,那为什么他可以修改呢?因为我们这个buff法可读可写。那待会儿呢,我们通过debug可以看到它的变化,一会呢,我们会看它的变化,好吧,待会我们可以看到的变化,也就是说你一定要知道,我们在进行这个操作的时候呢,不可以超过这个limit。
06:03
对,那么position呢,简单的理解成就是当前的位置,它表示的是下一个要被读或者写的元素的索引,每次读写读写缓冲区数据都会改变这个值并对,并为下次读写做准备。也就这个poson呢,他在读的时候可能发生变化,在写的时候呢,也有可能发生变化。Mark呢,它是一个标记啊,一旦float,呃,一旦flip了过后呢,它就作废了,这个mark一般来讲我们。不去改动它,就是很少去呃主动的去修改,那我现在呢,画了一个示意图,帮助同学们理解,因为时间的关系,我就已经画好了,比如说同学们看刚才我们就以刚才这个案例来进行说明,前面呢,我们举了一个叫做basic。Basic buffer,大家看,当我创建这么一句话过后呢,就这这一条语句执行以后,你可以认为在内存里面创建了有这么一个五个空间,这是一个数组。
07:09
对,也就是这次HB那个数组,然后呢,Position呢,它就指向了零,也就是说你将来要读或者要写的时候呢,先对零下边为零的这个位置进行操作,而你刚刚创建的时候呢,这个capacity派其实是等于五的,为什么呢?为什么等于五呢?就它的容量是五,因为你这写的是五,同时呢,同学们,同时这个limit也是五,为什么是五呢?因为他就表示说,如果你现在要向这个数组或者像这个buffer里面写数据,最多不能超过五,注意这个limit是不可以超过的啊。不能超过这个极限,就是说你最多呢只能操作到。四这个位置。好,那现在呢,口说无凭,我们给大家进行一个debug,大家一下就明白,其实这个东西你只要debug一下,一目二了然,现在呢,我们来debug一下,我在这下了一个断点。
08:03
下一个断点,我们来看一下它这几个属性的变化,同学们可以看到当前没有执行这句话的时候呢,只有X就是传递的这个参数,下面我执行一句,当我们执行完这句话过后,同学们可以看到int buffer这一个对象就创建好了,HB就是我们所说的那一个存放数据的数组,你看此时此刻。是不是有五个空间啊。那么都是零,默认是零,同学们可以看到,此时此刻这个mark呢等于负一,Position等于零,Limit等于五,大家看这里啊,一定要看清楚了,就这几个数据。Mark等于负1055 mark呢,一般它是用的一个标记的啊,它是用来做一个标记的,那么PO0代表我目前要,呃,就说如果你要写入的话呢,是要对这个位置进行写明白了吧,那么limit呢,就是你在整个这个操作过程中不能超过下边为五的位置,或者说你也可以理解成不能超过五个都行,CAC就是它容量,现在我们开始往下执行。
09:05
来走一个下一步,当我们执行完了过后,大家看执行往里面放一个数据过后,你发现position变成一了,也就是说。也就是说此时此刻你执行完一次过后呢,这边这个地方就支了,支了一个零,同时position后羿。明白了吧,好,紧接着我们继续往下看,再继续往下走,我就快速的走一下啊,你看走走走走。走走走,好,大家看,福利我还没有执行,在这个过程中,你们看到position就变到五了。Position就变的,但是这个五呢,其实是已经和厘米的相等了,就不能再超过它了,对不对,也就是说这个地方你可以这样理解。怎么理解呢?就是这边是放到二,放了过后它后移,放了四往后,放了六往后移,在这个位置呢,放一个八往后移。
10:02
也也就是说现在你可以认为position现在呢,其实它是等于五的,呃,不是不是认为啊,就是等于五的,而这个五呢,就已经跟这个limit相等了,不能超过它,因此它就不能再操作了,那这个时候呢,同学们。来看一下哈,来看一下此时此刻。我们现在整个这个标记大家也理解了,我我我是怎么来的,那么一旦这个flip,呃,这个呃,这个呃,Flip一旦操作了反转,会发生一个什么事情呢?我们来看一下这个动作,这个函数哈,它要做的事情是这么几句话,我回到这来把代码。给大家放过来。是不是也就是说他首他首先会把这个limit,就把这个position的值付给这个limit,表示什么意思呢?表示你待会在读的时候。读读数据。就是下次操作的时候啊,下一个过程操作读数据不能超过这个这个五了,因为你现在这个数据已经写到这个position不是已经变成五了吗?对,你放了五个数据,那你在读的时候呢,也不能超过五,Position变成零,也就是说现在这个position呢,它会。
11:15
怎么样啊,它会移动到最先前,那你在读的时候呢,也是针对这个position所在的位置进行读取,那就是第一个就读取的是。呃,就是这个。这个数组里面的第一个元素哪个数组呢?就是同学们看到的这个数组的第一个元素当然是零了,对不对?好,这个我就不再多说,好紧接着我们继续往往下来看吧,看是不是这样子的啊。好,我往下执行一把。当我们。诶,这个地方为什么紫晴他跑那儿去了呢?啊,因为我在这动态加了一句话,是不是我们就直接看这就行了,因为当时我们在没有debug之前,没有结束的时候,我加了一段代码,所以说他跑到哪去了,你不用管它,往下看看这里。
12:02
同学们看,当我执行了一个反转,反转操作过后,同学们看这里是不是跑变成零了。Limit还是五这个15好,下面呢,我们就一个个读取,读取的时候呢,这个跑式也会向后移动,好,我们来看一下往下走吧。好,你看。Position变成了一读了一个,对不对,读了一个变成一再继续读。变成二,你你们看这就行了,同学们看下面不要看上面了,因为上面我刚才加入了几句话,所以说这个位置就不对了,走走你看变成三了吧,P变成三了,到P变成三,它就不停的在读数据嘛,赌数据。接着继续往下看这个terminal,看有没有输出数据。好,这一轮不看字儿了啊。就看这个第八个了,好接着往下看走。好,大家看position已经到四了,再读一个。再读一个过后呢,这个抛式就等于五了,等于五它就要退出来了。
13:02
往下走,那就退出了这个语句啊,就退到这就相当于退出我们这程序了,对不对,因为你刚才这个外语语句已经执行完毕了,这个时候呢,Position通过刚才的一系列的读取,它又到哪去了呢。他又到这,诶不要把这个移过来。他又到了我们数组的最后。整个读取就结束了。他就这样子的。对好,呃,这个刚才这个看起来有点怪哈,因为刚才呢,我们动态加了一句,我们再来第bug一下,快速的过一下就行了。看一下就行了啊。走起来。好的往下走,你看这儿。对吧,把它打开再看一下。就看这几个参数的变化。好,就看这几个参数的变化走是吧,现在变四了,变四。好变五,退出,退出反转,反转过后position变零。
14:05
又开始读,你看读一次position呢,就会增加变一,Position变二。跑的是三。Position变四,Po变五,跳出来。结束。好,同学们,那关于这一块。这几个参数我相信同学们都应该明白了,也就是说,这个buffer之可以,之所以又可以读和写,就主要是靠这几个属性的变化来控制的。接着继续往下看。那么buff份呃及其子类它有哪些方法呢?有有些比较重要的方法,我给同学们标出来哈,这几个方法用的比较多一点。后面呢,我们还会用到我标成这个红色capacity position,还有我们可以设置磁缓冲器的位置,比如说我想从哪个位置开始读取,我也可以通过在这设置一个位置,我跳着读,你比如说我在我我们这个,呃,刚才这个图,比如说。
15:03
Position呢,现在是本身是一,我不想从第一个位置开始读,我直接到第二个位置读,可不可以呢?也是可以的,你比如说同学们,我给大家演示一个小案例,打个比方。我一反转过后,我一反转过后,我直接把这个position设一个位置,对我从一开始读,那同学们想一想,如果这样读的话,是不是我读的就只有就相当于从第二个元素开始读取了,因为你所以为一,其实第二个元素我们试一下。那这个时候读取的数据呢,就应该是2468。看一下。同学们可以看到这输出的应该是二十六八,明白这个意思了吧,很简单哈,很简单,接着继续往下看它其他几个方法,还有像limit也可以设置limit,比如说我想嗯,打个比方我呃,我position是这,但是呢,我不想读这么多,我只想读到。第三个位置,这你只要把limit给他修改一下就可以了,比如说我在这再设置一下。
16:03
我问同学们,这时候我输出我读取的是什么数据,同学们来想一想哈,来走一个。也得理你。啊,Limit我这儿可以设置的。对,然后呢,我设置到四。收到三吧。呃,我请同学们呃,思考一下,此时此刻我在这边读取,会读取到哪些数据呢?是不是下边唯一的这个地方是要读渠道的,二要读渠道二要读渠道三呢。三要不要读渠道?同学们想一想。对不对,要不要读渠道。是不是我们说不能超过这个这个位置啊,所以说我们看一下到底是输出几个元素呢,运行。哎,我们看运行走起来好,我们看一下。肯定是有变化的,对不对,你看这时候读到二和四,因为你在把它制成三的时候,三是不可以超过的。也也就是说它不能超过这个三,那只能在二这个位置了。
17:02
对不对,也就它读取两个元素就推出来了,明白哈,其他的我就不一不一个一个一个的去测试了,来看,继续往下说。你再比如说下面的这几个clean。Flip。可令这个方法呢是清除缓存区,注意清除缓存区,即将各个标记位恢复到初始状态,但是数据并没有真正的擦除。什么意思呢?就是说。我现在把这个缓缓存去一清除,那这个数据就会恢复到最初的状态,但是数据本身呢,它并没有擦除,也就是说你如果再写的话呢,它只是把原型数据给覆盖掉而已。反转缓存区力是不是已经讲过了,对还有几个像这个。是不是这个我们也用了has a remain。还有is read only,判断这个缓冲区是不是只读的,也就是说,我们将来还可以把一个缓冲区设置成只读。
18:00
还有在1.6引入的hands,这用的也比较多,对。还有这个也有用的比较多,这个A呢是返回磁缓中去底层实现数组,直接把这个数组返回来。紧接着我们继续往下看。下边呢,还有一个bit buffer,呃,我简单说一下,因为从前面我们可以看到,呃,Buffer下面的子类呢很多,其其实我们知道对于Java中的基本数据除外呢,Buffer都有一个对应的,呃,这个就是说。对应类型的一个buffer buffer类最常用的显然是bit buffer,因为bit buffer呢是字节buffer,而我们网络传输其实都是底层,都是以字节形式进行传输的,因此呢,Bad buffer在后面使用是最多的。我们来看一下他常用的方法,哪些有呢?我把常用的标出来,标出红色哈。Alloc allocate directory创直接创建一个冲区,还有这个是allocate设置缓冲区的初始容量,还有哪些呢?这四个也用的比较多,我们后面都会用。
19:08
Get。Get还有put put也就get呢,如果我们是这种方法get,你看我们这边代码这部get,这个get呢,它是相当于说在底层自己去修改这个position,那如果说你这个get呢,相当于说我可以指定去获取到某个position的数据。对,那么put也是一样的,Put呢,我们在如果调这个put方法是从当前位置上。从当前位置上这个这个put put这写错了啊添加。添加put之后呢,Position会自动加一,而这个put呢,它从绝对位置上put,那不会造成我们position的变化。OK,这因为你把这个位置指定清楚了,他知道是在哪放,然后呢,本身这个位置就不会变化了,而这个position也会变化,OK。
20:03
好的,那这就是我们缓冲区的内容,就说到这,我们可以可以同学们有兴趣呢,在下面自己去试一下各个方法好不好。我现在把刚才讲的buffer的内容呢,做一个简单的梳理。刚才我们讲了哪些内容呢?Buffer的内容我们梳理一下。缓冲区的基本介绍说了一下。缓冲区的基本介绍。走起来。啊,这地方又出问题了。为什么他嗯。他老这样子。缓冲区的基本介绍。放起来。缓冲区是什么呢?它的本质哈,它的本质其实呢,就是一个内存块对不对。是一个可读写的内存块。你也有些地方呢,你也可以理解成是个容器对象,而这个容器对象里面呢,它都有一个数组,对吧。
21:06
这边有一个相应的示意图,我也给大家拿过来。表示了我们缓冲区channel还有程序之间的关系。下面继续来说。然后呢,我们说了一下buffer的buffer类及其子类有哪些,以及它常用的一些方法对不对。嗯,这个呢,应该是标题二的。第一个是。这个把这个图拿过来就行。接过来,好。Buffer呢,它是个顶级类,它下面呢有很多子类,这些子类呢,都会对应我们Java的基本数据类型,呃,除了布丁没有,其他都有。紧接着继续往下梳理,下边呢,我们用了一个案例来说明了一下buffer里面四个最重要的属性分别表示什么含义,Mark position limit capacity用案例给大家追追了一下第八个一把。
22:10
给他来一个标号二一,这么是二才对。好的,那这边。讨厌哈。把这个地方调一下。这个地方应该是二。好,这样他就对应上了。那么这个,呃,他们属性是什么概念呢?我在这举了例子,这次为了快捷一点,我直接把它拿过来好吧。用debug的形式展示了他们之间的变化关系。第三点呢,我们又说了buffer一些重要的方法有哪些?方法一览表。是不是?
23:00
把buffer的呃,常用的方法给大家梳理了一下,放哪呢就放这好,我标红的就是比较重要的,同学们可以在课后自己试一下。把buffer常用的方法说完了以后呢,我们又说了一个,后边用的最多的一个,它的子类叫bit buffer,因为实际上在网络传输的时候呢,其实都是以字节的形式来传输的,所以说by buffer其实使用的最多的,我们又单独的说了一下。放这就可以了。对,Bad buffer。那bad buffer,诶我们看看这是。缓冲区。好的,By buffer。Bed buffer就应该是标号为三才对。那前面这个呢,应该标号为三好,稍微改一下。这就可以了。By buffer better buffer常用的方法呢,有些呃,比较重要的,我也给他标红了。
24:03
后边呢,我们会用到哈。这边尤其要注意到,如果我们get后面带的有一个索引,那么这就是从绝对位置取,如果你没有带的话呢,它从当前位置取了过后,这个position会加一。同学们可以去试一下,Put也是一样的道理。好的同学们,那关于我们缓冲区这块就给它说到这里,后面在案例里面呢,我们还会再提到它,在加深对它的认识,这一讲我们就先说到这。
我来说两句