Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung des Codes und Textes des Java NIO-Puffers

Detaillierte Erläuterung des Codes und Textes des Java NIO-Puffers

黄舟
黄舟Original
2017-03-31 11:09:121641Durchsuche

Ein Pufferobjekt ist ein Container für eine feste Datenmenge. Ein Kanal ist der Eingang, über den E/A-Übertragungen erfolgen, und ein Puffer ist die Quelle oder das Ziel dieser Datenübertragungen.

Puffer-Grundlagen

Alle Puffer verfügen über vier

Eigenschaften, die Informationen über die darin enthaltenen Datenelemente liefern.

Zwischen diesen vier Eigenschaften besteht immer die folgende Beziehung:

0 <= mark <= position <= limit <= capacity
Das Bild unten ist ein neu erstellter ByteBuffer:


Die Position ist auf 0 und die Kapazität und Obergrenze auf 10 eingestellt, um das letzte Byte zu übergeben, das der Puffer aufnehmen kann. Das Tag ist zunächst undefiniert. Die Kapazität ist festgelegt, die anderen drei Eigenschaften können jedoch bei Verwendung des Puffers geändert werden.

Das Folgende ist die Methodensignatur von Buffer:

public abstract class Buffer {

    public final int capacity() {
    }

    public final int position() {
    }

    public final Buffer position(int newPosition) {
    }

    public final int limit() {
    }

    public final Buffer limit(int newLimit) {
    }

    public final Buffer mark() {
    }

    public final Buffer reset() {
    }

    public final Buffer clear() {
    }

    public final Buffer flip() {
    }

    public final Buffer rewind() {
    }

    public final int remaining() {
    }

    public final boolean hasRemaining() {
    }

    public abstract boolean isReadOnly();

    public abstract boolean hasArray();

    public abstract Object array();

    public abstract int arrayOffset();

    public abstract boolean isDirect();
}
Die oben aufgeführte Buffer-

API enthält keine get()- oder put()-Funktionen. Jede Buffer-Klasse verfügt über diese beiden Funktionen, aber die Parametertypen, die sie annehmen, und der Datentyp, den sie zurückgeben, sind für jede Unterklasse eindeutig, sodass sie nicht in der Buffer-Klasse der obersten Ebene abstrakt deklariert werden können.

Das Folgende ist die Deklaration von ByteBuffer:

public abstract class ByteBuffer extends Buffer implements Comparable
{
    // This is a partial API listing
    public abstract byte get( );
    public abstract byte get (int index);
    public abstract ByteBuffer put (byte b);
    public abstract ByteBuffer put (int index, byte b);
}
Ein Beispiel betrachtet die Speicherung von ByteBuffer:

buffer.put((byte)&#39;H&#39;).put((byte)&#39;e&#39;).put((byte)&#39;l&#39;).put((byte)&#39;l&#39;).put((byte)&#39;o&#39;);

Wenn Sie die folgende Operation ausführen:

buffer.put(0,(byte)&#39;M&#39;).put((byte)&#39;w&#39;);

Wenn der Puffer voll ist und um den Inhalt auszulesen, müssen wir den Puffer umdrehen und die Flip-Methode aufrufen. Das Folgende ist die Flip-Methode in ByteBuffer:

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

Die Funktion rewind() ähnelt flip(), hat jedoch keinen Einfluss auf die Obergrenzeneigenschaft. Es setzt lediglich den Positionswert auf 0 zurück. Sie können rewind() verwenden, um die Daten im umgedrehten Puffer erneut zu lesen.

Die Methode hasRemaining() gibt zurück, ob die Obergrenze des Puffers derzeit erreicht ist. Die Methode

remaining() gibt den Abstand zur Obergrenze zurück.

Die Markierung des Puffers ist vor dem Aufruf der Funktion mark() undefiniert und beim Aufruf wird die Markierung auf den Wert der aktuellen Position gesetzt. Die Funktion

reset() setzt die Position auf den aktuellen Markerwert. Wenn der Markierungswert undefiniert ist, führt der Aufruf von reset() zu einer InvalidMark

Exception-Ausnahme.

rewind( ), clear( ) und flip( ) verwerfen immer das Flag, d. h. auf -1 gesetzt.

Die notwendigen und ausreichenden Bedingungen dafür, dass zwei Puffer als gleich betrachtet werden, sind:

  • Die beiden Objekte sind vom gleichen Typ. Puffer, die unterschiedliche Datentypen enthalten, sind bei weitem nicht gleich, und Puffer sind niemals gleich Nicht-Pufferobjekten.

  • Beide Objekte haben die gleiche Anzahl verbleibender Elemente. Die Kapazitäten der Puffer müssen nicht gleich sein, ebenso wenig wie die Indizes der verbleibenden Daten in den Puffern. Die Anzahl der verbleibenden Elemente (von der Position bis zur Obergrenze) in jedem Puffer muss jedoch gleich sein.

  • Die Reihenfolge der verbleibenden Datenelemente, die von der Get()-Funktion zurückgegeben werden sollen, muss in jedem Puffer konsistent sein.

Puffer erstellen

//分配一个容量为 100 个 char 变量的 Charbuffer
CharBuffer charBuffer = CharBuffer.allocate (100);

char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
//这段代码构造了一个新的缓冲区对象,但数据元素会存在于数组中。
这意味着通过调用 put()函数造成的对缓冲区的改动会直接影响这个数组,而且对这个数组的任何改动也会对这 个缓冲区对象可见。

CharBuffer.wrap(array, offset, length);可以指定 position 和 length
über allocate() oder wrap() Buffers Von Funktionen erstellte Puffer sind normalerweise indirekt, und indirekte Puffer verwenden Backup-Arrays. hasArray() Gibt zurück, ob dieser Puffer über ein zugängliches Backing-Array verfügt.

Puffer kopieren

Einige Kopierpuffer-APIs:

public abstract class CharBuffer extends Buffer implements CharSequence, Comparable {
	// This is a partial API listing
	public abstract CharBuffer duplicate( );
	public abstract CharBuffer asReadOnlyBuffer( );
	public abstract CharBuffer slice( );
}

duplicate() 函数创建了一个与原始缓冲区相似的新缓冲区。两个缓冲区共享数据元素,拥有同样的容量,但每个缓冲区拥有各自的位置,上界和标记属性。对一个缓冲区内的数据元素所做的改变会反映在另外一个缓冲区上。如果原始的缓冲区为只读,或者为直接缓冲区,新的缓冲区将继承这些属性。

如下示例:

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		buffer.position(3).limit(6).mark().position(5);
		CharBuffer dupeBuffer = buffer.duplicate();
		System.out.println(dupeBuffer.position());
		System.out.println(dupeBuffer.limit());
		dupeBuffer.clear();
		System.out.println(dupeBuffer.position());
		System.out.println(dupeBuffer.limit());
	}

//out
5
6
0
8

asReadOnlyBuffer() 函数来生成一个只读的缓冲区图。

代码说明如下:

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		CharBuffer dupeBuffer = buffer.asReadOnlyBuffer();
		System.out.println(dupeBuffer.isReadOnly());
		dupeBuffer.put(&#39;S&#39;);//只读buffer调用抛出异常
	}

//out
true
Exception in thread "main" java.nio.ReadOnlyBufferException
	at java.nio.HeapCharBufferR.put(HeapCharBufferR.java:172)
	at nio.test.TestMain.main(TestMain.java:10)

slice() 创建一个从原始缓冲区的当前位置开始的新缓冲 区,并且其容量是原始缓冲区的剩余元素数量(limit-position)。这个新缓冲区与原始 缓冲区共享一段数据元素子序列。分出来的缓冲区也会继承只读和直接属性。

public static void main(String[] args) {
		CharBuffer buffer = CharBuffer.allocate(8);
		buffer.position(3).limit(5);
		CharBuffer sliceBuffer = buffer.slice();
	}

字节缓冲区

在 java.nio 中,字节顺序由 ByteOrder 类封装。

ByteOrder.nativeOrder() 方法返回 JVM 运行的硬件平台字节顺序。

直接缓冲区

只有字节缓冲区有资格参与 I/O 操作。

I/O 操作的目标内存区域必须是连续的字节序列。

直接缓冲区被用于与通道和固有 I/O 例程交互。

直接字节缓冲区通常是 I/O 操作最好的选择。直接字节缓冲区支持 JVM 可用的最高效 I/O 机制。非直接字节缓冲区可以被传递给通道,但是这样可能导致性能耗。通常非直接缓冲不可能成为一个本地 I/O 操作的目标。如果向一个通道中传递一个非直接 ByteBuffer 对象用于写入会每次隐含调用下面的操作:

  1. 创建一个临时的直接 ByteBuffer 对象。

  2. 将非直接缓冲区的内容复制到直接临时缓冲中。

  3. 使用直接临时缓冲区执行低层次 I/O 操作。

  4. 直接临时缓冲区对象离开作用域,并最终成为被回的无用数据。

直接缓冲区时 I/O 的最佳选择,但可能比创建非直接缓冲区要花费更高的成本。直接缓冲区使用的内存是通过调用本地操作系统方面的代码分配的, 过了标准 JVM 。

ByteBuffer.allocateDirect() 创建直接缓冲区。isDirect() 返回是否直接缓冲区。

视图缓冲区

视图缓冲区通过已存在的缓冲区对象实例的工方法来创建。这种图对象维护它自己的属性,容量,位置,上界和标记,但是和原来的缓冲区共享数据元素。

ByteBuffer 类允许创建图来将 byte 型缓冲区字节数据映射为其它的原始数据类型。

public abstract CharBuffer asCharBuffer( );
public abstract ShortBuffer asShortBuffer( );
public abstract IntBuffer asIntBuffer( );
public abstract LongBuffer asLongBuffer( );
public abstract FloatBuffer asFloatBuffer( );
public abstract DoubleBuffer asDoubleBuffer( );

看如下一个例子的示意图:

ByteBuffer byteBuffer = ByteBuffer.allocate (7).order (ByteOrder.BIG_ENDIAN);
CharBuffer charBuffer = byteBuffer.asCharBuffer( );

public class BufferCharView {
       public static void main (String [] argv)  throws Exception  {
          ByteBuffer byteBuffer = ByteBuffer.allocate (7).order (ByteOrder.BIG_ENDIAN);
          CharBuffer charBuffer = byteBuffer.asCharBuffer( );
          // Load the ByteBuffer with some bytes
          byteBuffer.put (0, (byte)0);
          byteBuffer.put (1, (byte)&#39;H&#39;);
          byteBuffer.put (2, (byte)0);
          byteBuffer.put (3, (byte)&#39;i&#39;);
          byteBuffer.put (4, (byte)0);
          byteBuffer.put (5, (byte)&#39;!&#39;);
          byteBuffer.put (6, (byte)0);
          println (byteBuffer);
          println (charBuffer);
       }
       // Print info about a buffer
       private static void println (Buffer buffer)  {
		  System.out.println ("pos=" + buffer.position() + ", limit=" +
          	buffer.limit() + ", capacity=" + buffer.capacity() + ": &#39;" + buffer.toString( ) + "&#39;");
	}
}

//运行 BufferCharView 程序的输出是:
//pos=0, limit=7, capacity=7: &#39;java.nio.HeapByteBuffer[pos=0 lim=7 cap=7]&#39;
//pos=0, limit=3, capacity=3: &#39;Hi!

数据元素视图

ByteBuffer 类为每一种原始数据类型 供了存取的和转化的方法:

public abstract class ByteBuffer extends Buffer implements Comparable {
	public abstract char getChar();

	public abstract char getChar(int index);

	public abstract short getShort();

	public abstract short getShort(int index);

	public abstract int getInt();

	public abstract int getInt(int index);

	public abstract long getLong();

	public abstract long getLong(int index);

	public abstract float getFloat();

	public abstract float getFloat(int index);

	public abstract double getDouble();

	public abstract double getDouble(int index);

	public abstract ByteBuffer putChar(char value);

	public abstract ByteBuffer putChar(int index, char value);

	public abstract ByteBuffer putShort(short value);

	public abstract ByteBuffer putShort(int index, short value);

	public abstract ByteBuffer putInt(int value);

	public abstract ByteBuffer putInt(int index, int value);

	public abstract ByteBuffer putLong(long value);

	public abstract ByteBuffer putLong(int index, long value);

	public abstract ByteBuffer putFloat(float value);

	public abstract ByteBuffer putFloat(int index, float value);

	public abstract ByteBuffer putDouble(double value);

	public abstract ByteBuffer putDouble(int index, double value);
}

假如一个 bytebuffer 处于如下状态:

那么 int value = buffer.getInt();

实际的返回值取决于缓冲区的当前的比特排序(byte-order)设置。更具体的写法是:

int value = buffer.order (ByteOrder.BIG_ENDIAN).getInt( );

这将会返回值 0x3BC5315E,同时:

int value = buffer.order (ByteOrder.LITTLE_ENDIAN).getInt( );

返回值 0x5E31C53B

如果您试图获取的原始类型需要比缓冲区中存在的字节数更多的字节,会抛出 BufferUnderflowException。

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Codes und Textes des Java NIO-Puffers. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn