Java 如何避免制作ByteBuffer的防御性副本?
我有一个类,它接受ByteBuffer作为构造函数参数。有没有一种方法可以避免制作防御性拷贝,以确保缓冲区不会被修改超过该点Java 如何避免制作ByteBuffer的防御性副本?,java,immutability,nio,Java,Immutability,Nio,我有一个类,它接受ByteBuffer作为构造函数参数。有没有一种方法可以避免制作防御性拷贝,以确保缓冲区不会被修改超过该点 isReadOnly()不保证原始所有者不会修改缓冲区。更糟糕的是,似乎没有办法将ByteBuffer子类化。有什么想法吗?唯一真正的方法是,正如您所说的,buf.asReadOnlyBuffer(),然后将其传递给构造函数。除此之外,没有其他选项,尽管您可以将内容复制到新的ByteBuffer,然后将其传递。不会避免复制,但可能: 使用预填充的预分配ByteBuffer
isReadOnly()不保证原始所有者不会修改缓冲区。更糟糕的是,似乎没有办法将ByteBuffer子类化。有什么想法吗?唯一真正的方法是,正如您所说的,
buf.asReadOnlyBuffer()
,然后将其传递给构造函数。除此之外,没有其他选项,尽管您可以将内容复制到新的ByteBuffer
,然后将其传递。不会避免复制,但可能:
这并不能完全回答这个问题,但是对于某些用法(例如,如果您主要尝试强制执行“按合同设计”),它可能已经足够好了,而且效率更高。对于其他用途,它将不起作用,效率可能会低得多 在构造过程中,保存ByteBuffer的哈希代码 final int originalBBHashCode=byteBuffer.hashCode()
然后,在代码中要验证ByteBuffer没有更改的几个关键位置,验证ByteBuffer.hashCode()==originalBBHashCode。如果不是,抛出一个异常。坦白地说,我很想抛出ConcurrentModificationException,因为这是您正在模仿的行为,但YMMV。这是我目前能做的最好的:
/**
* Helper functions for java.nio.Buffer.
* <p/>
* @author Gili Tzabari
*/
public final class Buffers
{
/**
* Returns a ByteBuffer that is identical but distinct from the original buffer.
* <p/>
* @param original the buffer to copy
* @return an independent copy of original
* @throws NullPointerException if original is null
*/
public static ByteBuffer clone(ByteBuffer original)
{
Preconditions.checkNotNull(original, "original may not be null");
ByteBuffer result = ByteBuffer.allocate(original.capacity());
ByteBuffer source = original.duplicate();
source.rewind();
result.put(source);
try
{
source.reset();
result.position(source.position());
result.mark();
}
catch (InvalidMarkException unused)
{
// Mark is unset, ignore.
}
result.position(original.position());
result.limit(original.limit());
return result;
}
/**
* Returns an array representation of a buffer. The returned buffer may, or may not, be tied to
* the underlying buffer's contents (so it should not be modified).
* <p/>
* @param buffer the buffer
* @return the remaining bytes
*/
public static byte[] toArray(ByteBuffer buffer)
{
if (buffer.hasArray() && !buffer.isReadOnly() && buffer.position() == 0
&& buffer.remaining() == buffer.limit())
{
return buffer.array();
}
ByteBuffer copy = buffer.duplicate();
byte[] result = new byte[copy.remaining()];
copy.get(result);
return result;
}
/**
* Prevent construction.
*/
private Buffers()
{
}
}
/**
*java.nio.Buffer的助手函数。
*
*@作者Gili Tzabari
*/
公共最终类缓冲区
{
/**
*返回与原始缓冲区相同但不同的ByteBuffer。
*
*@param-original要复制的缓冲区
*@返回原件的独立副本
*@original为null时抛出NullPointerException
*/
公共静态ByteBuffer克隆(ByteBuffer原始)
{
先决条件。checkNotNull(原件,“原件不得为空”);
ByteBuffer结果=ByteBuffer.allocate(original.capacity());
ByteBuffer source=original.duplicate();
source.rewind();
结果。put(来源);
尝试
{
source.reset();
result.position(source.position());
result.mark();
}
捕获(InvalidMarkException未使用)
{
//标记未设置,忽略。
}
result.position(原始.position());
result.limit(原始.limit());
返回结果;
}
/**
*返回缓冲区的数组表示形式。返回的缓冲区可以绑定到,也可以不绑定到
*基础缓冲区的内容(因此不应修改)。
*
*@param buffer缓冲区
*@返回剩余的字节
*/
公共静态字节[]toArray(字节缓冲区)
{
if(buffer.hasArray()&&&!buffer.isReadOnly()&&buffer.position()==0
&&buffer.remaining()==buffer.limit())
{
返回buffer.array();
}
ByteBuffer copy=buffer.duplicate();
字节[]结果=新字节[copy.remaining()];
复制。获取(结果);
返回结果;
}
/**
*防止施工。
*/
专用缓冲区()
{
}
}
我还向Oracle提交了一个功能请求:+1。不错的良好实践问题。听起来收件人需要的是一个写时拷贝字节缓冲区。即使构造函数收到一个只读缓冲区,它也无法保证缓冲区不会被原始所有者(保留写访问权)修改。所以你还是被迫做一份防御性的拷贝。