如何避免制作ByteBuffer的防御性副本?

时间:2011-10-03 15:28:19

标签: java immutability nio

我有一个将ByteBuffer作为构造函数参数的类。有没有办法避免制作防御性副本,以确保缓冲区不会在该点之后被修改?

ByteBuffer.isReadOnly()不保证原始所有者不会修改缓冲区。更糟糕的是,似乎没有办法将ByteBuffer子类化。有什么想法吗?

4 个答案:

答案 0 :(得分:4)

唯一真正的方法是,如你所说,buf.asReadOnlyBuffer(),然后将其传递给构造函数。除此之外没有其他选择,尽管您可以将内容的副本复制到新的ByteBuffer中,然后传递它。

答案 1 :(得分:2)

这是我现在能做的最好的事情:

/**
 * 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()
    {
    }
}

我还向Oracle提交了一项功能请求:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7130631

答案 2 :(得分:1)

不要避免复制,但可能:

  1. 使用预先填充的预分配的ByteBuffers池
  2. 允许 作者类的构造函数允许传入的“副本” ByteBuffer,但让类使用池中的ByteBuffer来移动 应用启动/关闭的Alloc / Dealloc成本。这种方式只需支付记忆费用。

答案 3 :(得分:0)

这并没有完全回答这个问题,但是,对于某些用法(例如,如果你主要是试图强制执行“按合同设计”),它可能足够好,效率更高。对于其他用途,它将不起作用,可能效率低得多。

在构造函数中,保存ByteBuffer的hashCode

final int originalBBHashCode = byteBuffer.hashCode();

然后,在代码中要验证ByteBuffer未更改的几个关键位置,验证byteBuffer.hashCode()== originalBBHashCode。如果没有,抛出异常。坦率地说,我很想抛出一个ConcurrentModificationException,因为这是你模仿的行为,但是YMMV。