Ответ 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
и необходимости обеспечения безопасности потоков.