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