在Java中将3个字节转换为整数

11
  1. 我想在Java中将字节转换为整数。 我希望假设这些字节是无符号字节。 假设如果

    byte a = (byte)0xFF;
    
    int r = (some operation on byte a);
    

    r的值应该是255,而不是十进制中的-1。

  2. 然后我想从3个字节创建int值。 假设如果

  3. byte b1 = (byte)0x0F;
    
    byte b2 = (byte)0xFF;
    
    byte b3 = (byte)0xFF;
    
    int r = (some operation in bytes b1, b2 and b3);
    

    那么r应该是0x000FFFFF。字节b1将被放置在整数值的高3位位置,字节b3将被放置在整数值的低1位位置。同时,我的b1将从0x000x0F范围内变化,其他字节将从0x000xFF范围内变化,假设这些字节为无符号类型。如果字节b1大于0x0F,我将仅提取最低4位。简而言之,我希望从3个字节中提取int,但仅使用3个字节中的20位(来自b2和b3的总共16位以及b1的最低4位)。由于我们是从3个字节中创建int并假设它们是无符号类型,因此int r必须为正数。

5个回答

6

在这里,您需要小心符号扩展 - 不幸的是,在Java中,字节是有符号的(据我所知,这只会带来麻烦)。

因此,您需要进行一些掩码操作。

int r = (b3 & 0xFF) | ((b2 & 0xFF) << 8) | ((b1 & 0x0F) << 16);

谢谢Harold,我用你的解决方案得到了正确的答案。能否请您解释一下为什么要反转顺序,我的意思是从上面的b1开始,它给出了32640,这就是@ppeterka发布的解决方案。 - nullptr
@user1508907,顺序并不重要,但ppeterka的答案可能存在一个问题,即+的绑定比<<更强。 - harold
是的,我明白了。ppeteka没有使用括号。而且由于运算符的优先级规则,解决方案出现了混乱。 - nullptr

3
我想你希望得到无符号字节值。
int r = ((b1 & 0xF) << 16) | ((b2 & 0xFF) << 8) | (b3 & 0xFF);

每个字节都需要遮罩并向右位移相应的位数。

2
这很容易使用位移运算符和二进制AND实现。你只想使用b1的低4位,这正是b1 & 0x0F所做的。其余部分都是将位移动到不同的位置。
int r = ( (b1 & 0x0F) << 16) + ((b2 & 0xFF) << 8) + (b3 & 0xFF)

编辑 正如@harold所指出的,之前的解决方案(在低字节上没有0xFF掩码)会导致由于符号扩展而产生异常...

编辑2 哦天啊,每次处理这些时我总是被操作符优先级打击...

推荐阅读:


我尝试了上面的代码-public class Main {public static void main(String[] args) { byte b1 = (byte) 0x0f; byte b2 = (byte) 0xff; byte b3 = (byte) 0xff; int r = (b1&0x0F<<16) + (b2 & 0xFF)<<8 + (b3 & 0xFF); // 输出 - r: 32640 // 我想要 r: 1048575 System.out.println("r: "+r); }}它给了我32640,但我想要1048575。 - nullptr
谢谢你,但是你的解决方案是错误的。当我从b3开始而不是b1时,它给出了正确的答案,根据哈罗德的说法。使用你的解决方案会得到32640,但我想要1048575。 - nullptr
假设 b1 = ABb2 = CDb3 = 0E,你想要 AB CD 0E 还是 0E CD AB - jlordo
@jlordo,我想要0B CD 0E,我只想使用b1的低4位。 - nullptr
@user1508907 发现了我的解决方案中的错误并进行了修复。现在有一个通用的解决方案来解决你的问题... - jlordo
@user1508907 找到了(太明显了,我得向自己道歉,再次犯了同样的错误) - ppeterka

1
这是一个“仅换挡”的版本:
int r = ((b1 << 28) >>> 12) | (b2 << 8) | b3;

将左移28位会截取掉前4位,然后右移12位将其还原为净16位左移。

我测试了这段代码,它可以正常工作 :)


你能解释一下通过过度移位你希望实现什么吗? - Germann Arlington
哇,将位移36位以去掉前4位 :) 邪恶 :) 我喜欢!每天学到新东西真是一种享受! - ppeterka
这将会进行符号扩展到第20位。如果你不想这样,可以使用>>> - Peter Lawrey
@Bohemian,你可以像ppeterka在他/她的回答中所示那样使用简单的掩码(&)来剪切。 - logoff
@PeterLawrey 没错,顺便说一下,我也把我的移位量搞错了 :(. 现在已经修复了(并测试过)。 - Bohemian

1

我比较了一些答案,因为我很好奇哪个是最快的。

看起来 Bohemian 的方法是最快的,但我无法解释为什么第一次运行时它慢了 11%。

PS.:我没有检查答案的正确性。

以下是代码:

public class Test
{

  public static void main(String[] args)
  {
    final int RUNS = 10;
    final int TRIPLE = 3;
    final int N = 100000000;

    byte[] bytes = new byte[TRIPLE * 32768]; // 96 kB

    Random r = new Random();
    r.nextBytes(bytes);

    List<ByteConvertTester> testers = Arrays.asList(new Harold(), new Bohemian(), new Ppeterka());

    for (int i = 0; i < RUNS; i++)
    {
      System.out.println("RUN#" + i);
      System.out.println("----------------------");
      Integer compare = null;
      for (ByteConvertTester tester : testers)
      {
        System.out.println(tester.getClass().getSimpleName());
        long time = testAndMeasure(tester, bytes, N);
        System.out.print("time (in ms): " + time);
        if (compare != null) {
          System.out.println(" SpeedUp%: " + (double) ((int) (10000 * (1.0d - (double) time / compare))) / 100);
        } else {
          compare = (int) time;
          System.out.println();
        }
      }
      System.out.println("----------------------");
    }
  }

  private static long testAndMeasure(ByteConvertTester bct, byte[] bytes, int loops)
  {
    Calendar start = Calendar.getInstance();
    int r;
    for (int i = 0; i < loops; i += 3)
      r = bct.test(bytes[i % bytes.length], bytes[(i + 1) % bytes.length], bytes[(i + 2) % bytes.length]);

    Calendar end = Calendar.getInstance();
    long time = (end.getTimeInMillis() - start.getTimeInMillis());
    return time;
  }
}

interface ByteConvertTester
{
  public int test(byte msb, byte mid, byte lsb);
}

class Harold implements ByteConvertTester
{
  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return (lsb & 0xFF) | ((mid & 0xFF) << 8) | ((msb & 0x0F) << 16);
  }
}

class Bohemian implements ByteConvertTester
{
  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return ((msb << 28) >>> 12) | (mid << 8) | lsb;
  }
}

class Ppeterka implements ByteConvertTester
{

  @Override
  public int test(byte msb, byte mid, byte lsb)
  {
    return ((msb & 0x0F) << 16) + ((mid & 0xFF) << 8) + (lsb & 0xFF);
  }
}

OUTPUT

RUN#0
----------------------
Harold
time (in ms): 489
Bohemian
time (in ms): 547 SpeedUp%: -11.86
Ppeterka
time (in ms): 479 SpeedUp%: 2.04
----------------------
RUN#1
----------------------
Harold
time (in ms): 531
Bohemian
time (in ms): 521 SpeedUp%: 1.88
Ppeterka
time (in ms): 537 SpeedUp%: -1.12
----------------------
RUN#2
----------------------
Harold
time (in ms): 531
Bohemian
time (in ms): 539 SpeedUp%: -1.5
Ppeterka
time (in ms): 532 SpeedUp%: -0.18
----------------------
RUN#3
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 519 SpeedUp%: 1.89
Ppeterka
time (in ms): 531 SpeedUp%: -0.37
----------------------
RUN#4
----------------------
Harold
time (in ms): 527
Bohemian
time (in ms): 519 SpeedUp%: 1.51
Ppeterka
time (in ms): 530 SpeedUp%: -0.56
----------------------
RUN#5
----------------------
Harold
time (in ms): 528
Bohemian
time (in ms): 519 SpeedUp%: 1.7
Ppeterka
time (in ms): 532 SpeedUp%: -0.75
----------------------
RUN#6
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 520 SpeedUp%: 1.7
Ppeterka
time (in ms): 532 SpeedUp%: -0.56
----------------------
RUN#7
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 520 SpeedUp%: 1.7
Ppeterka
time (in ms): 533 SpeedUp%: -0.75
----------------------
RUN#8
----------------------
Harold
time (in ms): 530
Bohemian
time (in ms): 521 SpeedUp%: 1.69
Ppeterka
time (in ms): 532 SpeedUp%: -0.37
----------------------
RUN#9
----------------------
Harold
time (in ms): 529
Bohemian
time (in ms): 527 SpeedUp%: 0.37
Ppeterka
time (in ms): 530 SpeedUp%: -0.18
----------------------

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接