Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中是否存在不可变位集?_Java_Collections_Guava - Fatal编程技术网

Java中是否存在不可变位集?

Java中是否存在不可变位集?,java,collections,guava,Java,Collections,Guava,是否有Java库提供不可变位集?我没有找到任何,无论是番石榴还是谷歌都没有。你可以用BigInteger。它是不可变的,并且有位操作方法。您可以使用,因为它有setBit,testBit和clearBit通过扩展java.util.BitSet并使用删除修饰符方法抛出不支持的异常或空块,可以很容易地从java.util.BitSet创建一个几乎不可变的位集 但是,由于存储有效数据的位集字段不是final,因此必须应用其中一种安全发布习惯用法来实现线程安全(复制自): 从静态初始值设定项初始化对

是否有Java库提供
不可变位集
?我没有找到任何,无论是番石榴还是谷歌都没有。

你可以用BigInteger。它是不可变的,并且有位操作方法。

您可以使用,因为它有
setBit
testBit
clearBit
通过扩展java.util.BitSet并使用删除修饰符方法抛出不支持的异常或空块,可以很容易地从java.util.BitSet创建一个几乎不可变的位集

但是,由于存储有效数据的位集字段不是final,因此必须应用其中一种安全发布习惯用法来实现线程安全(复制自):

  • 从静态初始值设定项初始化对象引用
  • 将对它的引用存储到易失性字段或原子引用中
  • 将对它的引用存储到正确构造的对象的最终字段中
  • 将对它的引用存储到由 锁
另一个解决方案是创建一个新的ImmutableBitSet类,将一个位集作为字段(带有最终修饰符)嵌入其中,并将嵌入对象的读取器方法委托给新类

请注意,后一种解决方案不违反Liskow替换原则,而第一种解决方案则违反了Liskow替换原则。

解决方案:

将位集存储在专用字段中,并使用克隆公共方法公开它:

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);
    }

    ...
}