Есть ли ImmutableBitSet в Java? - PullRequest
       2

Есть ли ImmutableBitSet в Java?

11 голосов
/ 11 августа 2011

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

Ответы [ 7 ]

6 голосов
/ 11 августа 2011

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

3 голосов
/ 29 сентября 2011

Я решил подвести итог всех ответов:

Я не вижу способа сделать все идеально, т. Е. Получить неизменный подкласс 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 и необходимости обеспечения безопасности потоков.

3 голосов
/ 11 августа 2011

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

сохранить 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;
}
3 голосов
/ 11 августа 2011

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

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

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

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

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

2 голосов
/ 11 августа 2011

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

2 голосов
/ 11 августа 2011

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

1 голос
/ 18 апреля 2013

Я реализовал это на основе org.apache.lucene.util.OpenBitSet из проекта Apache Lucene здесь

http://www.dishevelled.org/bitset

http://www.dishevelled.org/bitset/apidocs/index.html

...