2011-10-03 76 views
17

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

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

+1

+1。很好的实践问题。 – helios

+0

听起来像接收者需要的是写入时复制字节缓冲区。 –

回答

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

4

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

+1

即使构造函数接收到只读缓冲区,也无法保证缓冲区不会被原始所有者(保留写入访问权限)修改。所以你仍然不得不做一个防御性的副本。 – Gili

1

不避副本,但也许是:

  1. 使用预分配的ByteBuffers预填充池
  2. 允许 构造作者的类的允许传入 “复制” ByteBuffer,但有类使用池中的ByteBuffer将应用程序启动/关闭的Alloc/Dealloc成本移动到 。只需以这种方式支付memcopy费用。
0

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

在你的构造,节省掉字节缓冲区的的hashCode

最终诠释originalBBHashCode = byteBuffer.hashCode();

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