在学习JavaNIO中看到关于Buffer的部分时提到buffer调用clear()方法不会真正的删除掉buffer中的数据,只是把position移动到最前面,同时把limit调整为capacity,忽然想到,如果不是真的删除掉buffer中的数据,那么如果之前写入buffer中五个字符:
CharBuffer buf = CharBuffer.allocate(48);
buf.put(new char[] {'a', 'b', 'c', 'd', 'e'});
但是只读取了一个:
System.out.println(buf.get()); // 此时输出为 a
如果这个时候clear一下,重新写入一个新的字符,再次读取第一个应该是我们新写入的字符:
buf.clear();
buf.put('g');
buf.flip();
System.out.println(buf.get()); // 此时输出为 g
如果此时之前的数据没有真的清除,那么应该可以继续读取上一次未读取的内容,这样的话就仅仅是从0位置覆盖原来的buffer进行写入,再次读取:
System.out.println(buf.get()); // 预期输出为 b
此时理所当然的报了错:
g
java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Buffer.java:500)
at java.nio.HeapCharBuffer.get(HeapCharBuffer.java:135)
at TestBuffer.main(TestBuffer.java:13)
实践后才想起来一个重点,当第二次写入新的字符时,要重新读取执行flip()方法时会将limit改为新的position,根本没有给我们机会(真的没机会吗?往后看...)去读buffer中的旧数据。
此时完整测试代码如下:
import java.nio.CharBuffer;
public class TestBuffer {
public static void main(String[] args) {
CharBuffer buf = CharBuffer.allocate(48);
buf.put(new char[] {'a', 'b', 'c', 'd', 'e'});
buf.flip();
System.out.println(buf.get());
buf.clear();
buf.put('g');
buf.flip();
System.out.println(buf.get());
System.out.println(buf.get());
}
}
此时完整运行结果如下:
但是我们真的无法读取buffer中的旧数据了吗?
对此我查看源码后发现,limit竟然可以进行手动的设置:
可见limit可以设置为一个小于capacity且大于0的任意整数,为了读取到我们前面存的五个字符中剩下的四个,我们将limit改为5并读取5次,再次实验:
import java.nio.CharBuffer;
public class TestBuffer {
public static void main(String[] args) {
CharBuffer buf = CharBuffer.allocate(48);
buf.put(new char[] {'a', 'b', 'c', 'd', 'e'});
buf.flip();
System.out.println(buf.get());
buf.clear();
buf.put('g');
buf.flip();
buf.limit(5);
System.out.println(buf.get()); // 输出 g
System.out.println(buf.get()); // 输出 b
System.out.println(buf.get()); // 输出 c
System.out.println(buf.get()); // 输出 d
System.out.println(buf.get()); // 输出 e
}
}
实验结果: