我是个Java新手,开始用BitSet和ByteBuffer实现一个UDP发送器,因为某些原因,我得到了我意想不到的行为.

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.BitSet;

public class Main
{
    public static void main(String[] args) {
        
        ByteBuffer out = ByteBuffer.allocate(2);
        BitSet byt = new BitSet(8);
        byt.set(0, true);
        byt.set(1, false);
        out.put(byt.toByteArray());
        byt.set(0, true);
        byt.set(1, false);
        byt.set(2, true);
        out.put(byt.toByteArray());
        
        System.out.println("First byte is " + out.array()[0]+ " second is " + out.array()[1]);
    }
}

我从哪里得到的输出

First byte is 1 second is 5

我认为这是不对的,因为字符顺序是错误的

当我try 运行此命令时:

public class Main
{
    public static void main(String[] args) {
        
        ByteBuffer out = ByteBuffer.allocate(2);
        BitSet byt = new BitSet(8);
        byt.set(0, false);
        byt.set(1, false);
        out.put(byt.toByteArray());
        byt.set(0, true);
        byt.set(1, false);
        byt.set(2, true);
        out.put(byt.toByteArray());
        
        System.out.println("First byte is " + out.array()[0]+ " second is " + out.array()[1]);
    }
}

输出将更改为

First byte is 5 second is 0

我认为这是正确的答案.

请注意,更改只发生在第7行,而字节的顺序也发生了更改.

快速测试是herehere

我对Java还是个新手.因此,这可能是一场巨大的误会.不管怎样,谢谢你!

推荐答案

BitSet.toByteArray()创建字节数组,该数组具有表示BitSet所需的最小长度.您可以在文档中阅读:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/BitSet.html#toByteArray()

byte[] bytes = s.toByteArray();
then bytes.length == (s.length()+7)/8 and
s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)
for all n < 8 * bytes.length.

而s.long()是:

返回此BitSet的"逻辑大小":BitSet中最高设置位的索引加1.如果BitSet不包含设置位,则返回零.

因此,从本质上讲,如果您在位集中只存储了False,那么toByteArray()将返回空array.

ByteBuffer将在您放入字节时填充它们.因此,字节的存储顺序与您调用.put方法的顺序完全相同.

现在,让我们遵循您的代码示例:

大小为2的ByteByffer,最初为:

| x | x |
  0   1

X表示它是空的

然后创建BitSet:[true, false, false, false, false, false, false, false],这是数组:[1].然后将其放入您的ByteBuffer中:

| 1 | x |
  0   1

在第一个条目中,您现在有1.

然后创建第二个位集:[true, false, true, false, false, false, false, false],即[5](2^0+2^2=1+4=5).然后将其放入BytBuffer:

| 1 | 5 |
  0   1

因此,您的输出是:‘第一个字节是1秒是5’.这是正确的.

我认为这是不对的,因为字符顺序是错误的

我不认为你的问题与字符顺序有任何关系,如果你期望看到‘第一个字节是5,第二个是1’,那么就把字节的添加顺序换成字节缓冲区.

现在,让我们遵循第二个示例:

大小为2的ByteByffer,最初为:

| x | x |
  0   1

然后是BitSet和[false, false, false, false, false, false, false, false],这是二进制中的0.但是,由于BitSet没有设置位,因此BitSet.toByteArray将生成空array.

因此,ByteBuffe没有变化,它仍然是空的:

| x | x |
  0   1

PUT到ByteBuffer后,第二位设置为[true, false, true, false, false, false, false, false],即[5]:

| 5 | x |
  0   1

在这里,因为前BitSet个没有添加任何内容,所以我们只看到添加第二个字节的结果.

因此,您的问题源于BitSet在使用toByteArray()时如何生成array.您可能会考虑不使用BitSet,而使用其他一些类,请参阅下面的内容,以获得一些提示:Java BitSet and byte[] usage

[编辑] 对第二个示例的修复可以手动考虑到BitSet.toByteBuffer可以返回零数组并手动添加[0]array.当然,对于第二个字节也可以这样做.

    ByteBuffer out = ByteBuffer.allocate(2);
    BitSet byt = new BitSet(8);
    byt.set(0, false);
    byt.set(1, false);
    
    byte[] byteArr = byt.toByteArray();
    if(byteArr.length == 0) {
        out.put((byte)0);
    } else {
        out.put(byteArr);
    }
    
    byt.set(0, true);
    byt.set(1, false);
    byt.set(2, true);
    
    byteArr = byt.toByteArray();
    out.put(byteArr);
    
    System.out.println("First byte is " + out.array()[0]+ " second is " + out.array()[1]);

Java相关问答推荐

是否可以从@ TrustMapping中删除特定方法的基路径?

在Java 8之后,HashMap的最坏情况下时间复杂度仍然是O(n)而不是O(log n)?

将成为一个比较者.比较…在现代Java中,编译器会对`CompareTo`方法进行优化吗?

从技术上讲,OPC UA客户端是否可以通过转发代理将请求通过 tunel 发送到OPC UA服务器?

Java中是否有某种类型的池可以避免重复最近的算术运算?

FALSE:它应该在什么时候使用?

如何在运行时动态创建表(使用Java、JPA、SprringBoot)

为什么我的在一个范围内寻找素数的程序不能像S所期望的那样工作

基于调车场算法的科学计算器

测试期间未执行开放重写方法

如何在EXCEL单元格中添加形状和文本

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

将JSON字符串转换为Java类

buildDir:File!&#的getter解决方案是什么?39.被抛弃

在使用具有不同成本的谓词调用allMatch之前对Java流进行排序会带来什么好处吗?

视图被推出线性布局-Android

在Java中将.GRF转换为图像文件

谷歌应用引擎本地服务器赢得';t在eclipse上运行

如何使JOOQ渐变脚本不重新创建表未更改的类?

如何在 WebSphere Application Server 内的托管线程上运行 BatchEE 作业(job)?