Young Master and Girls Learn JavaIO: Buffer and Buff

brief introduction

The little sister and teacher are walking farther and farther along the way to learn NIO. The only thing that can help her is to give her full support when she needs it.Say nothing. Today we're talking about NIO's basic Buffer.Old fellow gave me a Buff.

What is Buffer

Little sister: Brother F, this Buffer is the sentence in our King's Canyon: Does the old fellow add a Buff to me?

Of course not. This Buffer is not another Buff. Buffer is the basis of NIO. Without Buffer there would be no NIO and without Buffer there would be no java today.

Because NIO reads data by Block, this Block can be considered a Buffer.We store data to be read and written in a Buffer to improve the efficiency of reading and writing.

More interesting and see:

More please visitwww.flydean.com

Remember what the underlying storage unit for java objects is?

Little sister: I know that the underlying storage unit of java objects is byte Byte.

Yes, let's look at Buffer's inheritance chart:

Buffer is an interface that has many implementations underneath it, including the most basic ByteBuffer and other Buffers encapsulated by other basic types.

Little sister: Brother F, isn't it enough to have ByteBuffer?What else type of Buffer do?

Young teacher and sister, Shanzhen is great, and sometimes they get tired of eating, they also need to change radish and cabbage. What do you think they did in Jiangnan during the Qianlong Period?

ByteBuffer is good, but it's the smallest unit on which we have the basic types Char, int, Double, Short and so on. For simplicity's sake, we also have a set of Buffers for them.

Buffer Advancement

Little sister: Brother F, since Buffer is a collection of these basic types, why not express it directly in combination?It seems redundant to encapsulate them into an object.

Since it makes sense to use Objects on the surface in an Object-oriented world, at the bottom, these encapsulated Buffer s contain some additional metadata information and provide some unexpected functionality.

The figure above lists several key Buffer concepts, Capacity, Limit, Position, and Mark.The bottom layer of a Buffer is an array. Let's take ByteBuffer as an example, and its bottom layer is:

final byte[] hb; 
  • Capacity represents the maximum number of elements that the Buffer can hold, which was set early in the creation of the Buffer and cannot be changed.
  • Limit represents the number of elements in a Buffer that can be accessed, that is, the number of elements that survive in a Buffer.
  • Position represents the index of the next accessible element, which can be updated automatically by the put and get methods.
  • Mark represents a historical index. When we call the mark method, we set Mark to the current position and restore the value of Mark to position by calling the reset method.

Create Buffer

Little sister: Brother F, is it troublesome to create so many Buffer s?Is there any quick way to use it?

Generally speaking, there are two ways to create a Buffer: allocate and wrap.

public void createBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        log.info("{}",intBuffer);
        log.info("{}",intBuffer.hasArray());
        int[] intArray=new int[10];
        IntBuffer intBuffer2= IntBuffer.wrap(intArray);
        log.info("{}",intBuffer2);
        IntBuffer intBuffer3= IntBuffer.wrap(intArray,2,5);
        log.info("{}",intBuffer3);
        intBuffer3.clear();
        log.info("{}",intBuffer3);
        log.info("{}",intBuffer3.hasArray());
    }

Allocate can allocate a space for Buffer, and wrap can also allocate a space for Buffer, except that the array behind this space is customized. wrap also supports methods for three parameters, offset and length.

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=7 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - true

hasArray is used to determine whether the bottom level of the Buffer is implemented as an array, and you can see that whether wrap or allocate is implemented as an array.

One thing to note is that, finally, we called the clear method, and after the clear method call, we found that the position and limit of the Buffer were reset.This means that the three parameter methods of wrap set only the initial values and can be reset.

Direct VS non-Direct

Little sister: Brother F, you said two ways to create Buffers, but both Buffers are behind arrays. Are there any Buffers that are not arrays?

Naturally, but only ByteBuffer does.ByteBuffer has a allocateDirect method that assigns Direct Buffer s.

Little sister: What is the difference between Direct and non-Direct?

Direct Buffer means that you don't need to copy another copy of the data in user space to operate directly in the virtual address mapping space.This is called Direct.The advantage of this is that it's fast.The disadvantage is that it takes up more resources when allocated and destroyed, and because Direct Buffer is not in user space, it is not subject to the garbage collection mechanism.

So in general, Direct Buffer is only used for data with large data volumes and long life cycles.

Look at the code:

public void createByteBuffer() throws IOException {
        ByteBuffer byteBuffer= ByteBuffer.allocateDirect(10);
        log.info("{}",byteBuffer);
        log.info("{}",byteBuffer.hasArray());
        log.info("{}",byteBuffer.isDirect());

        try (RandomAccessFile aFile = new RandomAccessFile("src/main/resources/www.flydean.com", "r");
             FileChannel inChannel = aFile.getChannel()) {
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
            log.info("{}",buffer);
            log.info("{}",buffer.hasArray());
            log.info("{}",buffer.isDirect());
        }
    }

In addition to allocateDirect, you can also get a Directed MapdByteBuffer using FileChannel's map method.

The example above outputs the results:

INFO com.flydean.BufferUsage - java.nio.DirectByteBuffer[pos=0 lim=10 cap=10]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true
INFO com.flydean.BufferUsage - java.nio.DirectByteBufferR[pos=0 lim=0 cap=0]
INFO com.flydean.BufferUsage - false
INFO com.flydean.BufferUsage - true

Buffer's Daily Operations

Little sister: Brother F, it seems that Buffer is really a bit complicated, so what are Buffer's operations?

There are many Buffer operations, so let's talk about them later.

Writing data to Buffer

Writing data to Buffer calls Buffer's put method:

public void putBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer.array());
        intBuffer.put(0,4);
        log.info("{}",intBuffer.array());
    }

Because the put method returns an IntBuffer class, Buffer's put method can be concatenated like Stream.

At the same time, we can specify where put is.Code output above:

INFO com.flydean.BufferUsage - [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
INFO com.flydean.BufferUsage - [4, 2, 3, 0, 0, 0, 0, 0, 0, 0]

Reading data from Buffer

The get method is used to read the data, but we need to call the flip method before the get method.

What does the flip method do?As mentioned above, a Buffer has a position and limit field, which automatically points to the next element as a get or put method, and a limit indicates how many elements are available in the Buffer.

If we want to read Buffer's value, it will start with positon and end with limit:

public void getBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        intBuffer.flip();
        while (intBuffer.hasRemaining()) {
            log.info("{}",intBuffer.get());
        }
        intBuffer.clear();
    }

You can use hasRemaining to determine if there is another element.Clear the Buffer by calling clear for next use.

rewind Buffer

Rewind is similar to flip, except that rewind does not change the limit value and only resets position to zero.

public void rewindBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer);
        intBuffer.rewind();
        log.info("{}",intBuffer);
    }

Output of the results above:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=10 cap=10]

Compact Buffer

Buffer also has a compact method, which, by its name, means compact, which assigns a Buffer value from the current position to the limit to a position with position 0:

public void useCompact(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        intBuffer.flip();
        log.info("{}",intBuffer);
        intBuffer.get();
        intBuffer.compact();
        log.info("{}",intBuffer);
        log.info("{}",intBuffer.array());
    }

Code output above:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=3 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=2 lim=10 cap=10]
INFO com.flydean.BufferUsage - [2, 3, 3, 0, 0, 0, 0, 0, 0, 0]

duplicate Buffer

Finally, let's talk about duplicate, asReadOnly Buffer, and slice.

A duplicate is a copy of the position, limit, and mark of the original Buffer, which shares the original data with the original Buffer.So when you modify the duplicate, the Buffer will also modify the original Buffer.

If you use asReadOnlyBuffer, you will not be allowed to modify the Buffer after the copy.

Slce is also readOnly, but it copies from the position of the original Buffer to the limit-position.

public void duplicateBuffer(){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer);
        IntBuffer duplicateBuffer=intBuffer.duplicate();
        log.info("{}",duplicateBuffer);
        IntBuffer readOnlyBuffer=intBuffer.asReadOnlyBuffer();
        log.info("{}",readOnlyBuffer);
        IntBuffer sliceBuffer=intBuffer.slice();
        log.info("{}",sliceBuffer);
    }

Output results:

INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBufferR[pos=3 lim=10 cap=10]
INFO com.flydean.BufferUsage - java.nio.HeapIntBuffer[pos=0 lim=7 cap=7]

summary

Today, I introduced Buffer's principle and basic operation to my little sister and teacher.

Examples of this article https://github.com/ddean2009/learn-java-io-nio

Author: Fldean Programs

Links to this article: http://www.flydean.com/java-io-nio-buffer/

Source: Fldean's blog

Welcome to my Public Number: program stuff, more exciting waiting for you!

Tags: Java Spring github

Posted on Tue, 09 Jun 2020 18:13:43 -0400 by ccjob2