2011-10-03 26 views
17

Tôi đã có một lớp học có một ByteBuffer như là một đối số constructor. Có cách nào để tránh tạo bản sao phòng thủ để đảm bảo rằng bộ đệm không bị sửa đổi trong quá khứ không?Làm thế nào để tránh làm cho bản sao phòng thủ của ByteBuffer?

ByteBuffer.isReadOnly() không đảm bảo rằng chủ sở hữu ban đầu sẽ không sửa đổi bộ đệm. Để làm cho vấn đề tồi tệ hơn, có vẻ như không phải là một cách để phân lớp ByteBuffer. Bất kỳ ý tưởng?

+1

1. Câu hỏi hay về thực hành tốt. – helios

+0

Âm thanh như những gì người nhận cần là bộ đệm byte sao chép trên ghi. –

Trả lời

2

này là tốt nhất tôi có thể làm bây giờ:

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

Tôi cũng đã đệ đơn yêu cầu tính năng với Oracle: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7130631

4

Cách thực tế duy nhất là, như bạn nói, buf.asReadOnlyBuffer(), sau đó chuyển thông tin này vào hàm tạo. Không có lựa chọn nào khác ngoài việc này, mặc dù bạn có thể sao chép nội dung vào một ByteBuffer mới, sau đó vượt qua điều đó.

+1

Thậm chí nếu hàm tạo nhận bộ đệm chỉ đọc, nó không có cách nào đảm bảo rằng bộ đệm sẽ không bị chủ sở hữu ban đầu sửa đổi (người giữ lại quyền truy cập ghi). Vì vậy, bạn vẫn bị buộc phải tạo một bản sao phòng thủ. – Gili

1

Không tránh một bản sao, nhưng có lẽ:

  1. Sử dụng một hồ bơi điền sẵn của ByteBuffers trước được phân bổ
  2. Cho phép constructor của lớp của tác giả để cho phép một 'bản sao' của đến ByteBuffer, nhưng có lớp sử dụng một ByteBuffer từ các hồ bơi để di chuyển Alloc/Dealloc chi phí để khởi động ứng dụng/tắt máy. Chỉ thanh toán một bản ghi nhớ theo cách này.
0

Điều này không hoàn toàn trả lời câu hỏi, nhưng, đối với một số cách sử dụng (ví dụ: nếu bạn chủ yếu cố gắng thực thi "thiết kế theo hợp đồng"), nó có thể đủ tốt và hiệu quả hơn. Đối với các tập quán khác, nó sẽ không hoạt động và có thể kém hiệu quả hơn nhiều.

Trong constructor của bạn, tiết kiệm đi hashCode của ByteBuffer

thức int originalBBHashCode = byteBuffer.hashCode();

Sau đó, tại một số địa điểm quan trọng trong mã của bạn nơi bạn muốn xác minh rằng ByteBuffer không thay đổi, hãy xác minh rằng byteBuffer.hashCode() == originalBBHashCode. Nếu không, hãy ném một ngoại lệ. Thành thật mà nói, tôi sẽ bị cám dỗ để ném một ConcurrentModificationException, vì đó là hành vi bạn đang bắt chước, nhưng YMMV.

Các vấn đề liên quan