Introduction to the

The only thing that can help her is to give her full support when she needs it. Without further ado, today’s introduction is NIO’s basic Buffer. Give me a Buff.

What is the Buffer

Brother F, does this Buffer mean “give me a Buff” as we said in The Valley of Kings?

Buffers are the foundation of NIO. Without buffers, there would be no NIO. Without Buffers, there would be no Java.

Since NIO reads data in blocks, each Block can be considered a Buffer. We store the data to be read and the data to be written in buffers to improve the efficiency of reading and writing.

More highlights:

  • Blockchain from getting started to Giving up series tutorials – with ongoing updates covering cryptography, Hyperledger, Ethereum,Libra, Bitcoin and more
  • Spring Boot 2.X Series tutorials: Learn Spring Boot from Scratch in seven days – continuous updates
  • Spring 5.X Series tutorials: Everything you can think of in Spring5 – constantly updated
  • Java Programmer from Handyman to Expert to God (2020 edition) – Ongoing updates with detailed articles and tutorials

For more, visit www.flydean.com

Remember what the underlying storage unit for Java objects is?

I know that. The underlying storage unit of Java objects is Byte.

Yes, let’s look at the Buffer inheritance diagram:

Buffer is an interface that has a number of implementations, including the most basic ByteBuffer and other buffers wrapped in the basic type.

Brother F, isn’t ByteBuffer enough? What else do I need buffers for?

Small teacher younger sister, shanzhen again good, also have tired of eating time, occasionally also want to change radish cabbage what, you think Qianlong xijiangnan have done what?

ByteBuffer is useful, but it is the smallest unit. We also have Char, int, Double, Short, and other basic types on top of it. For simplicity, we also have a set of buffers for them all.

The Buffer into the order

Brother F, since Buffer is a collection of these basic types, why not just express it as a combination? Encapsulating them as an object seems a bit redundant.

Since we are in the object-oriented world, it makes sense to use Object on the surface, but the underlying nature of these encapsulated buffers is that they contain some additional metadata information and provide some unexpected functionality.

The figure above lists the key concepts in Buffer, Capacity, Limit, Position, and Mark. The underlying nature of Buffer is an array. Let’s take ByteBuffer as an example. Its underlying nature is:

final byte[] hb; 
Copy the code
  • Capacity is the maximum number of elements that a Buffer can hold. This is set when the Buffer is created and cannot be changed.
  • Limit indicates the number of elements in the Buffer that can be accessed, that is, the number of surviving elements in the Buffer.
  • Position represents the index of the next element that can be accessed, and can be updated automatically with the PUT and GET methods.
  • Mark represents the historical index. When we call the Mark method, Mark will be set to the current position, and the value of Mark will be restored to position by calling the reset method.

Create a Buffer

Brother F, is it too much trouble to create so many buffers? Is there a quick way to use it?

Generally speaking, there are two ways to create buffers, one is called allocate and the other is called wrap.

public void createBuffer(a){
        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());
    }
Copy the code

Allocate allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer, wrap allocate space for Buffer.

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
Copy the code

HasArray is used to determine whether the underlying Buffer is an array implementation. As you can see, both WRAP and ALLOCATE are arrays.

Finally, we call the clear method. After the clear method is called, we find that the position and limit of the Buffer have been reset. This means that wrap’s three-argument methods are set to initial values and can be reset.

Direct VS non-Direct

F: You said there are two ways to create buffers, but both buffers have arrays in the background. Is there any Buffer that is not an array?

Naturally there is, but only ByteBuffer has it. ByteBuffer has an allocateDirect method that allocates Direct buffers.

What’s the difference between Direct and non-direct?

A Direct Buffer is a Buffer that operates directly in the virtual address mapping space without having to copy and copy data in user space. This is called Direct. The advantage of this is that it’s fast. The disadvantages are that it takes up more resources during allocation and destruction, and because the Direct Buffer is not in user space, it is not governed by the garbage collection mechanism.

Therefore, the Direct Buffer is usually used only for data with a large amount of data and a long lifetime.

Take a look at the code:

public void createByteBuffer(a) 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()); }}Copy the code

In addition to allocateDirect, you can also get a Direct MappedByteBuffer using the FileChannel map method.

The above example outputs:

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
Copy the code

Routine operation of Buffer

Brother F, it seems that Buffer is a bit complicated. What are the operations of Buffer?

There are many operations for Buffer, and we’ll explain them one by one.

Write data to Buffer

To write data to Buffer, call Buffer’s put method:

public void putBuffer(a){
        IntBuffer intBuffer= IntBuffer.allocate(10);
        intBuffer.put(1).put(2).put(3);
        log.info("{}",intBuffer.array());
        intBuffer.put(0.4);
        log.info("{}",intBuffer.array());
    }
Copy the code

Because the put method returns an IntBuffer, the put method of Buffer can be penalized like Stream.

Also, we can specify where put is. Output from the code 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]
Copy the code

Read data from Buffer

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

So what does the Flip method do? The Buffer has position and limit fields. Position points to the next element with a get or put method, and limit refers to the number of available elements in the Buffer.

If we were to read Buffer, we would start with positon and end with limit:

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

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

rewind Buffer

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

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

The result output above is:

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]
Copy the code

Compact Buffer

Buffer also has a compact method, which assigns the Buffer from position to limit to position 0:

public void useCompact(a){
        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());
    }
Copy the code

Output from the above code:

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]
Copy the code

duplicate Buffer

Finally, duplicate Buffer, asReadOnlyBuffer, and slice.

Duplicate is a duplicate of position, limit, and mark of the original Buffer, which shares the original data with the original Buffer. Therefore, the modified Buffer after duplicate will also modify the original Buffer.

If you use asReadOnlyBuffer, you are not allowed to modify the cached Buffer.

Slice is also readOnly, but copies the position from the original Buffer to limit-position.

public void duplicateBuffer(a){
        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);
    }
Copy the code

Output result:

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]
Copy the code

conclusion

Today, I introduced the principle and basic operation of Buffer.

Examples of this article github.com/ddean2009/l…

Author: Flydean program stuff

Link to this article: www.flydean.com/java-io-nio…

Source: Flydean’s blog

Welcome to pay attention to my public number: procedures those things, more wonderful waiting for you!