Как избежать создания защитных копий ByteBuffer? - PullRequest
19 голосов
/ 03 октября 2011

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

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

Ответы [ 4 ]

4 голосов
/ 03 октября 2011

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

2 голосов
/ 17 января 2012

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

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

1 голос
/ 03 октября 2011

Не избегает копирования, но возможно:

  1. Использовать предварительно заполненный пул предварительно выделенных байтовых буферов
  2. Разрешить конструктор класса автора, позволяющий «копировать» входящие ByteBuffer, но класс должен использовать ByteBuffer из пула для перемещения Alloc / Dealloc стоит для запуска / выключения приложения. Таким образом, оплачивайте только стоимость копии.
0 голосов
/ 04 октября 2011

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

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

final int originalBBHashCode = byteBuffer.hashCode ();

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

...