Java中是否存在不可变位集?
是否有Java库提供Java中是否存在不可变位集?,java,collections,guava,Java,Collections,Guava,是否有Java库提供不可变位集?我没有找到任何,无论是番石榴还是谷歌都没有。你可以用BigInteger。它是不可变的,并且有位操作方法。您可以使用,因为它有setBit,testBit和clearBit通过扩展java.util.BitSet并使用删除修饰符方法抛出不支持的异常或空块,可以很容易地从java.util.BitSet创建一个几乎不可变的位集 但是,由于存储有效数据的位集字段不是final,因此必须应用其中一种安全发布习惯用法来实现线程安全(复制自): 从静态初始值设定项初始化对
不可变位集
?我没有找到任何,无论是番石榴还是谷歌都没有。你可以用BigInteger。它是不可变的,并且有位操作方法。您可以使用,因为它有setBit
,testBit
和clearBit
通过扩展java.util.BitSet并使用删除修饰符方法抛出不支持的异常或空块,可以很容易地从java.util.BitSet创建一个几乎不可变的位集
但是,由于存储有效数据的位集字段不是final,因此必须应用其中一种安全发布习惯用法来实现线程安全(复制自):
- 从静态初始值设定项初始化对象引用李>
- 将对它的引用存储到易失性字段或原子引用中李>
- 将对它的引用存储到正确构造的对象的最终字段中
- 将对它的引用存储到由 锁
private final BitSet bits;
public BitSet bits(){
return (BitSet) bits.clone();
}
或:
就我个人而言,我更喜欢
EnumSet
而不是位集
。它实现为一个位字段,但具有一组具有强命名的API。这真是两全其美。番石榴确实提供了一个ImmutableEnumSet
我决定总结一下所有答案:
我认为没有办法让一切都变得完美,即获得位集
的不可变子类,以便equals
以线程安全的方式工作。我承认我没有在问题中陈述我所有的要求
从BitSet
继承并让所有的mutator方法抛出一个异常是很容易而且有效的。唯一的问题是从BitSet
调用的equals
本身不是线程安全的,因为它直接访问非最终继承字段。所有其他方法都可以通过下面描述的技巧实现线程安全
委派给位集
也很容易且有效,它唯一的问题是位集
不能等于不可变位集
。请注意,为了线程安全,代理必须存储在最后一个字段中
将继承和委派相结合看起来很有希望:
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)
不是线程安全的,因为它们直接访问非final字段。所以这只是一个徒劳的练习
如果想要实现所有的方法以及与可变位集的转换,那么使用
bitineger
是相当多的工作。因此,我推荐委派或继承,这取决于equals的期望行为和线程安全性的需要。我在这里基于apache lucene项目的org.apache.lucene.util.OpenBitSet实现了这样的方法
@Joachim Sauer对于我正在使用的位集
相同的东西,记住什么是开的,什么是关的。它应该是不可变的,因为它在创建后不应该被更改,并且必须是线程安全的。它应该有一个采用普通位集的构造函数。通过“what's on and what's off”,我们是在谈论一些预定义的特性/标志集吗?如果是这样,那么EnumSet
可能是一个好的解决方案。虽然它不是天生不变的,但您可以使用集合轻松创建一个不可修改的包装器。unmodifiableset()
@Joachim Sauer:我使用了两个这样的预定义集,它们是固定的,但我不想将它们全部转换为枚举(元素太多,写得太多,失去了灵活性)。写得太多?对我来说,听起来像是一份寻找和替换的工作。你失去了什么灵活性?好吧,这是你的选择。@Joachim Sauer:当然,搜索和替换不是一项要求很高的工作。关于灵活性:假设我需要表示一组canasta卡,所以我生成4乘以13,即52张卡。我可以做这么大的一个枚举,但是如果数据发生变化怎么办?也许有一天他们会改变,因为我现在做的不是canasta。我试过了,很简单。然而,我不认为我可以通过这种方式实现线程安全性-这里没有最终的结果。嘿!如果它是不可变的,那么它本质上是线程安全的。再看一遍。你的关键词是“最终”吗?你想用它做什么?它与线程安全无关。也许你会想到“同步”。无论如何,如果你愿意的话,你可以把它放在扩展类的方法上。是的,immutable意味着线程安全,但这只是因为。不,在任何情况下,我都不会混淆“最终”和“同步”。很抱歉,说“final”与“线程安全”无关是完全错误的。我的意思是“final”作为阻止方法重写或类扩展的关键字,它毕竟与线程安全有一些间接关系,但关系不大。但是我看到你想到了“final”,它阻止重新分配字段或局部变量,你是对的,它们与线程安全有更多的关系。但是,即使没有“最终”字段,如果字段实际上从未更改,对象也可以“有效地不可变”。删除修改器正是这样做的。java.util.Collections.unmodifiableList()做了类似的事情,但不是用扩展,而是用委托。我想,你错了。在46:10观看,看看如果省略final
会发生什么。好主意,但是。。。依赖于为每次访问使用可变副本可能会有点混乱。如果总是调用bits()
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);
}
...
}