Есть ли библиотека Java, предлагающая ImmutableBitSet
? Я не нашел ни одного, ни Гуаву, ни Google.
Есть ли ImmutableBitSet n Java?
Ответ 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
Ответ 7
Я реализовал такой на основе org.apache.lucene.util.OpenBitSet из проекта Apache Lucene здесь