Есть ли ImmutableBitSet n Java?

Есть ли библиотека Java, предлагающая ImmutableBitSet? Я не нашел ни одного, ни Гуаву, ни Google.

Ответ 1

Я решил составить резюме всех ответов:

Я не вижу возможности добиться совершенства, т.е. получить неизменный подкласс BitSet, так что equals работает в потокобезопасном режиме. Я признаю, что я не указал все свои требования в вопросе.

Унаследовать от BitSet и позволить всем методам мутанта исключить исключение легко и работает. Единственная проблема заключается в том, что equals, вызванный из BitSet сам по себе, не является потокобезопасным, так как он напрямую обращается к неотделимым унаследованным полям. Все другие методы можно сделать потокобезопасными с помощью трюка, описанного ниже.

Делегирование на BitSet также легко и работает, и его единственная проблема заключается в том, что BitSet не может быть равно ImmutableBitSet. Обратите внимание, что для безопасности потоков делегат должен храниться в конечном поле.

Объединение наследования и делегирования выглядит многообещающим:

public class ImmutableBitSet extends BitSet {
    private final ImmutableBitSet delegate;

    public ImmutableBitSet(BitSet original) {
        or(original); // copy original to this
        delegate = this; // initialize a final reference for thread safety
    }

    @Override // example mutator method
    public void and(BitSet set) {
        throw new UnsupportedOperationException();
    }

    @Override // example non-mutator method
    public boolean get(int bitIndex) {
        return delegate.getPrivate(bitIndex);
    }

    // needed in order to avoid endless recursion
    private boolean getPrivate(int bitIndex) {
        super.get(bitIndex);
    }

    ...
}

Это выглядит странно, но работает почти идеально. Вызов bitSet.equals(immutableBitSet) не является потокобезопасным, потому что они напрямую обращаются к нефинальным полям. Так что это было просто бесплодное упражнение.

Использование BitInteger - это довольно много работы, если вы хотите реализовать все методы и преобразовать в и из измененного BitSet. Поэтому я бы рекомендовал делегирование или наследование в зависимости от желаемого поведения equals и необходимости обеспечения безопасности потоков.

Ответ 2

Вы можете использовать BigInteger, так как он имеет setBit, testBit и clearBit.

Ответ 3

Легко сделать практически неизменный BitSet из java.util.BitSet, расширив его и выбив методы модификатора с помощью throws UnsupportedException или пустого блока.

Однако, поскольку поле BitSet, в котором хранятся эффективные данные, не final, вам необходимо применить один из безопасных идиом публикации для обеспечения безопасности потоков (скопировано из здесь):

  • Инициализация ссылки на объект из статического инициализатора;
  • Сохранение ссылки на него в поле volatile или AtomicReference;
  • Сохранение ссылки на него в конечное поле правильно построенного объекта
  • Сохранение ссылки на нее в поле, которое должным образом защищено замок.

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

Обратите внимание, что последнее решение не нарушает принцип заимствования Лискова, в то время как первый делает.

Ответ 4

Обходной путь:

храните BitSet в приватном поле и выставляйте его с помощью общедоступного метода клонирования:

private final BitSet bits;
public BitSet bits(){
    return (BitSet) bits.clone();
}

или

private final BitSet bits;
public BitSet bits(){
    BitSet clone = new BitSet();
    clone.or(bits);
    return clone;
}

Ответ 5

Возможно, вы можете использовать BigInteger. Он неизменен и имеет методы манипуляции бит.

Ответ 6

Лично я предпочитаю EnumSet над BitSet. Он реализован как бит-поле, но имеет API набора с сильным названием. На самом деле это лучшее из обоих миров. Guava предоставляет ImmutableEnumSet