在增长、收缩和克隆其值之后,Java位集的大小是多少?
让它成为Java中的在增长、收缩和克隆其值之后,Java位集的大小是多少?,java,memory-management,clone,bitset,Java,Memory Management,Clone,Bitset,让它成为Java中的bs1位集。 第一位设置为bs1。设置(0),然后其大小和长度分别为64和1。 设置第65位为bs1。设置(64),则其大小和长度分别为128和65 现在,如果我清除它的第65位bs1.clear(64),它的长度会回到1,但是它的大小会怎样呢? 如果克隆位集会发生什么?新版本的大小是默认的吗?更少的单词和更多的代码,在我看来,这个实验回答了这个问题: import java.util.BitSet; public class BitSetExperiment {
bs1
位集。第一位设置为
bs1。设置(0)
,然后其大小和长度分别为64和1。
设置第65位为bs1。设置(64)
,则其大小和长度分别为128和65
现在,如果我清除它的第65位bs1.clear(64)
,它的长度会回到1,但是它的大小会怎样呢?
如果克隆位集会发生什么?新版本的大小是默认的吗?更少的单词和更多的代码,在我看来,这个实验回答了这个问题:
import java.util.BitSet;
public class BitSetExperiment {
public static void main(String[] args) {
BitSet bs0=new BitSet();
BitSet bs1;
System.out.println("created:\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
bs0.set(15);
System.out.println("set(15):\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
bs0.set(63);
System.out.println("set(63):\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
bs0.set(86);
System.out.println("set(86):\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
bs0.clear(86);
System.out.println("clear(86):\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
bs0.clear(63);
System.out.println("clear(63):\tLength,Size bs0: "+bs0.length()+" , "+bs0.size());
System.out.println("Cloning to bs1...\n");
bs1=(BitSet)bs0.clone();
System.out.println("Length,Size bs0: "+bs0.length()+" , "+bs0.size());
System.out.println("Length,Size bs1: "+bs1.length()+" , "+bs1.size());
}
}
输出:
created: Length,Size bs0: 0 , 64
set(15): Length,Size bs0: 16 , 64
set(63): Length,Size bs0: 64 , 64
set(86): Length,Size bs0: 87 , 128
clear(86): Length,Size bs0: 64 , 128
clear(63): Length,Size bs0: 16 , 128
Cloning to bs1...
Length,Size bs0: 16 , 64
Length,Size bs1: 16 , 64
查看输出,我发现了两件事:
当您清除更重要的位时,位集不会调整其大小,但可能是使用另一种更复杂的机制完成的,正如蜘蛛@Boris在其评论中所建议的那样
克隆位集时,原始位集和克隆位都以尽可能小的分配表示(以64位的系数表示)
答案可能取决于实施情况。以下信息是通过阅读Java11源代码收集的
指定用于收缩位集的唯一API方法是trimToSize()
大多数(变异的)API方法可能会增加它的大小,但不会减少它
例外情况是用于Java对象序列化的clone()
和(private)readObject
和writeObject
方法。这些方法的行为取决于名为sizeistick
的私有字段,而该字段又取决于对象以前的历史记录
如果位集
是使用容量创建的,则它具有粘性大小。除非位集
超出其容量,否则大小将保持不变
- 克隆具有粘性大小的
位集时,克隆对象具有相同的大小,并且大小也是粘性的
- 克隆具有非粘性大小的
位集时,首先修剪对象,然后创建克隆。克隆的大小将是非粘性的
- 当使用粘性大小序列化
位集
时,序列化表单将保留该大小
- 使用非粘性大小序列化
位集
时,位集
将在序列化之前进行修剪
- 从序列形式反序列化
位集
时,其大小与序列形式的大小相同,并且粘性是试探性设置的
当大小为非粘性时,clone()
和writeObject
中发生的修剪有点令人惊讶,但(Java 11)代码就是这样做的。sizeisticky
字段上的注释部分解释了该行为
/**
* Whether the size of "words" is user-specified. If so, we assume
* the user knows what he's doing and try harder to preserve it.
*/
private transient boolean sizeIsSticky = false;
如果在边界翻转一点时,位集
修剪了其大小,则会降低性能。如果位集
要自动调整其大小,则可能会根据-进行调整,这比您的测试建议的要复杂一点。完全同意,Java很可能会实际调整位集,但不是在清除空间后立即进行。我将在答案中说明这种可能性