The Buffer class is the structural basis of Java.nio. A Buffer object is a container for a fixed number of data, the function of which is a memory, or a segmented transport area, where data can be stored and retrieved later. The buffer can be filled or deallocated. There is a buffer class for each non-Boolean raw data type, that is, the subclasses of buffer are: Bytebuffer, Charbuffer, DoubleBuffer, Floatbuffer, Intbuffer, Longbuffer, and Shortbuffer, there is no Booleanbuffer said. Although the buffer acts on the original data type they store, the buffer is very prone to processing bytes. Non-byte buffers can perform conversions from bytes or to bytes in the background, depending on how the buffer was created.
◇ Four properties of buffer
All buffers have four properties to provide information about the data elements they contain, which, although simple, is essential to memorize the heart: Capacity (Capacity): The maximum number of data elements that a buffer can hold. This capacity is set when the buffer is created and can never be changed. Upper bound (Limit): The first element of a buffer that cannot be read or written. When Buffering is created, the value of the limit equals the value of capacity. Assuming capacity = 1024, we set the limit = 512 in the program, indicating that the buffer capacity is 1024, but can neither read nor write since 512, so it is understood that the actual usable size of buffer is 512. Location (Position): The next index of the element to be read or written. The position is automatically updated by the corresponding get () and put () functions. The point to note here is that the location of the positon is starting from 0. Tag (Mark): a memo location. The mark is undefined before it is set (undefined). The use scenario is, assuming that there are 10 elements in the buffer, the current position of position is 2 (that is, if get is the third element), now just want to send the buffer between 6-10, at which point we can Buffer.mark (Buffer.position ()), The current position is recorded in Mark, then Buffer.postion (6), at which point the data sent to channel is 6-10. After sending, we can call Buffer.reset () to make position = mark, so here's mark is used to temporarily record the location. Keep in mind that when using Buffer, we are actually manipulating the values of these four properties. We found that the Buffer class did not include get () or put () functions. However, the subclasses of each Buffer have these two functions, but the types of arguments they take and the data types they return are unique to each subclass, so they cannot be declared abstractly in the top-level Buffer class. Their definitions must be complied with by subclasses of a particular type. Without special instructions, some of the things we're talking about here are examples of bytebuffer, and of course it has get () and put () methods.
◇ relative access and absolute access
Java code public abstract class Bytebuffer extends Buffer implements comparable {//this are a partial API listing public AB Stract byte get (); public abstract byte get (int index); Public abstract bytebuffer put (byte b); Public abstract bytebuffer put (int index, byte b); }
To see the code above, there are methods with no index parameters and methods with index parameters. Get and put without indexes, and after these calls are executed, the value of the position automatically advances. Of course, for put, if the call causes the position to exceed the upper bound more than once (note that it is limit instead of capacity), the bufferoverflowexception exception is thrown, and for get, if the position is not less than the upper bound (the same is limit instead of capacity), the bufferunderflowexception exception is thrown. This method without index parameters is called relative access, and relative access automatically affects the location attribute of the buffer. A method with an indexed parameter, called Absolute access, does not affect the location attribute of the buffer, but throws a Indexoutofboundsexception exception if you provide an index value that is out of range (negative or not less than the upper bound).
◇ Flip
We put the Hello string into a bytebuffer, as follows: Put Hello in Bytebuffer
Java code Bytebuffer buffer = bytebuffer.allocate (1024); Buffer.put ((byte) ' H '). Put ((byte) ' E '). put ((byte) ' L '). Put ((byte) ' O ');
At this point, Position = 5,limit = Capacity = 1024. Now we're going to read the data from the buffer in the right place, and we can put the position to 0, so where is the end of the string? Here's the upper bound. If you set the upper bound to the current position position, that is, 5, then limit is the end position. The upper bound property indicates the end of the buffer valid content. Manually Flip:
Java Code buffer.limit (Buffer.position ()). Position (0);
But this buffer flip from padding to release is designed by API designers, and they provide us with a very handy function: Buffer.flip (). In addition, the rewind () function is similar to flip () but does not affect the upper bound property, it simply sets the position value back to 0. The Buffer.flip () function is generally used when doing a buffer read operation.
◇ Release (drain)
The release here refers to the process by which the buffer is populated with data and then read out. It says, to read the data, first have to flip. So how to read it. Hasremaining () tells you whether the buffer is up to the upper bounds when the buffer is freed: the Hasremaining () function and the remaining () function have a close function.
Java code for (int i = 0; buffer.hasremaining (); i++) {Mybytearray[i] = Buffer.get (); }
Obviously, the code above always determines whether the element reaches the upper bound. We can do this: change the release process
Java code int count = buffer.hasremaining (); for (int i = 0; i < count; i++) {Mybytearray[i] = Buffer.get (); }
The second piece of code looks very efficient, but note that the buffer is not multi-threaded safe. If you want to use multithreading to access specific buffers at the same time, you need to synchronize before accessing the buffer. Therefore, the premise of using the second paragraph of code is that you have special control over the buffer.
◇buffer.clear ()
The clear () function resets the buffer to an empty state. Instead of changing any data element in the buffer, it simply sets the limit to the value of the capacity and sets the position back to 0.
◇compact (I do not know how to translate, compression.) Compact. )
Sometimes we just want to release part of the data that reads only part of the data. Of course, you can point the postion to the position of the first data you want to read, and set the limit to the position of the last element + 1. However, once the buffer object completes the fill and release, it can be reused. Therefore, once the buffer is read out, it has no use value.
Take mellow For example, fill it with mellow, but if we just want to read the llow. After reading, the buffer can be reused. The two positions of Me are useless for us. We can copy the llow to 0-3 and the Me is flushed off. But 4 and 5 are still O and W. Of course we can do it ourselves by getting and put, but the API provides us with a compact () function that is much more efficient than our own use of get and put.
Buffer before the Compact
Buffer.compact () makes the state diagram of the buffer as shown in the following illustration:
Buffer after the Compact
A few things have happened here: Data element 2-5 is copied to 0-3 locations, positions 4 and 5 are unaffected, but is now or has exceeded the current position and is therefore "dead". They can be overridden by subsequent put () calls. Position has been set to the number of data elements being replicated, that is, the buffer is now positioned in the latter position of the last "live" element in the buffer. The upper bound property is set to the value of the capacity, so the buffer can be filled again. The purpose of the call Compact () is to discard the data that has been freed, preserve the data that is not released, and make the buffer ready for the refill capacity. In this example, you can of course have read the Me before, that has been released.
◇ Comparison of buffers
Sometimes it is necessary to compare the data contained in two buffers. All buffers provide a regular equals () function to test the equality of two buffers, and a compareTo () function to compare buffers.
The necessary and sufficient conditions for two buffers to be equal are: two object types are the same. The buffer containing the different data types will never be equal, and the buffer will never be equal to a non-buffer object. Two objects are left with the same number of elements (limit-position). The buffer's capacity does not need to be the same, and the index of the remaining data in the buffer does not have to be the same. The sequence of remaining data elements that should be returned by the Get () function in each buffer ([position, limit-1] the sequence of elements corresponding to the position) must be consistent.
Two buffers that are considered to be equal
Two buffers that are thought to be unequal
The buffer also supports using the CompareTo () function to compare in dictionary order, which is, of course, the interface that all buffers implement java.lang.Comparable semantics. This also means that buffer arrays can be sorted by their contents by calling the Java.util.Arrays.sort () function.
Similar to Equals (), CompareTo () does not allow comparisons between different objects. But CompareTo () is stricter: If you pass an object of the wrong type, it throws a ClassCastException exception, but Equals () returns FALSE.
Comparisons are made for the rest of your data (from position to limit) for each buffer, in the same way they are in equals (), until an element of inequality is found or the upper bound of the buffer is reached. If a buffer is depleted before the unequal element is discovered, a shorter buffer is considered to be less than the longer buffer. Here's a question of order: The following results of less than 0 (the value of the expression is true) mean Buffer2 < Buffer1. Remember, this does not mean Buffer1 < buffer2.
Java code if (Buffer1.compareto (Buffer2) < 0) {/Do sth, it means Buffer2 < Buffer1,not Buffer1 < buffer2 do Sth (); }
◇ Bulk Mobile
The buffer is designed to transfer data efficiently, and moving one data element at a time is not efficient. As you can see in the following list of programs, the buffer API provides a function to move data elements out of your buffer in bulk:
Java code public abstract class Bytebuffer extends Buffer implements comparable {public bytebuffer get (byte[] DST); Public Bytebuffer get (byte[] DST, int offset, int length); Public final Bytebuffer put (byte[] src); Public Bytebuffer put (byte[] src, int offset, int length); }
as you can see in the above list of programs, the buffer API provides a function to bulk move data elements inside and outside the buffer. In the case of GET, it copies the contents of the buffer into the specified array, starting with the position, of course. The second form uses the offset and length parameters to specify the child intervals to copy to the destination array. These bulk moves have the same synthetic effect as the loops discussed earlier, but these methods may be much more efficient because the buffer implementation can move data using local code or other optimizations. &NBSP
Bulk Move always has the specified length. In other words, you always ask for a fixed number of data elements to be moved. Therefore, get (dist) and get (Dist, 0, dist.length) are equivalent. &NBSP
An exception occurs for data replication in the following situations: If the amount of data you require cannot be transmitted, then no data will be passed and the state of the buffer will remain unchanged. , while throwing bufferunderflowexception exceptions. If the data in the buffer is not enough to fully fill the array, you will get an exception. This means that if you want to pass a small buffer into a large array, you need to explicitly specify the length of the data remaining in the buffer. if the buffer has more data than the array can hold, you can read it repeatedly using the following code:
Java code byte[] Smallarray = new BYTE[10]; while (Buffer.hasremaining ()) {int length = Math.min (Buffer.remaining (), smallarray.length); Buffer.get (smallarray, 0, length); After each part of the data is fetched, the ProcessData method is called, and length represents the number of bytes of data processdata (Smallarray, length) actually fetched; }
The batch version of put () works similarly, except that it writes the elements in the array into the buffer, no longer repeating them here.
◇ Create buffer
Of the seven seed classes of Buffer, none of them can be directly instantiated, they are abstract classes, but they all contain static factory methods to create new instances of the corresponding classes. In this part of the discussion, take the Charbuffer class as an example and apply to the other six main buffer classes. The following is a key function for creating a buffer, common to all buffer classes (to replace the class name as needed):
Java code public abstract class Charbuffer extends Buffer implements Charsequence, comparable {//it is a partial API Li Sting public static Charbuffer allocate (int capacity); public static Charbuffer Wrap (char [] array); public static Charbuffer Wrap (char [] array, int offset, int length); Public Final Boolean hasarray (); Public final char [] array (); Public final int arrayoffset (); }
The new buffer is created by an assignment (allocate) or wrapper (wrap) operation. The assignment (allocate) operation creates a buffer object and allocates a private space to store the size of the data element. The wrapper (Wrap) operation creates a buffer object but does not allocate any space to store the data elements. It uses the array you provide as the storage space to store the data elements in the buffer. Demos
Java code //This code implicitly allocates a char array from the heap space as a backup storage to store 100 char variables. Charbuffer Charbuffer = charbuffer.allocate (m); /** * This code constructs a new buffer object, but the data element is present in the array. This means that changes to the slow * flush area caused by invoking the put () function will directly affect the array, and any changes to the array will be visible to the buffer object. */char [] myarray = new char [100]; charbuffer charbuffer = Charbuffer.wrap (myarray); /** * with offset The Wrap () function version with length as a parameter constructs a buffer that initializes the position and limit according to the value of the offset and length parameters that you provide. * This function does not, as you might think, create a buffer that occupies only one subset of the array. This buffer can access this array.