Подтвердить что ты не робот

Как избежать создания защитных копий ByteBuffer?

У меня есть класс, который принимает ByteBuffer как аргумент конструктора. Есть ли способ избежать создания защитных копий, чтобы гарантировать, что буфер не будет изменен после этой точки?

ByteBuffer.isReadOnly() не гарантирует, что первоначальный владелец не будет изменять буфер. Хуже того, не существует способа подкласса ByteBuffer. Любые идеи?

4b9b3361

Ответ 1

Это лучшее, что я мог сделать сейчас:

/**
 * 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 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

Единственный реальный путь - это, как вы говорите, buf.asReadOnlyBuffer(), а затем передать это в конструктор. Никакой другой вариант кроме этого, хотя вы могли бы сделать копию содержимого в новый ByteBuffer, а затем передать это.

Ответ 3

Не следует копировать, но возможно:

  • Используйте предварительно заполненный пул предварительно выделенных ByteBuffers
  • Разрешить конструктор класса Author, чтобы разрешить "копию" входящего ByteBuffer, но использовать класс ByteBuffer из пула для перемещения Alloc/Dealloc стоит на запуск/завершение работы приложения. Платите только расходы на память.

Ответ 4

Это не совсем отвечает на вопрос, но для некоторых применений (например, если вы в основном пытаетесь обеспечить "дизайн по контракту" ), это может быть достаточно хорошим и более эффективным. Для других применений это не сработает и может быть намного менее эффективным.

Во время вашего конструктора сохраните hashCode ByteBuffer

final int originalBBHashCode = byteBuffer.hashCode();

Затем в нескольких критических местах вашего кода, где вы хотите проверить, что ByteBuffer не изменился, убедитесь, что byteBuffer.hashCode() == originalBBHashCode. Если нет, выбросьте исключение. Честно говоря, у меня возникло бы желание бросить ConcurrentModificationException, так как это поведение, которое вы имитируете, но YMMV.