【问题标题】:Java Precedence - Casting and Bitwise OperatorsJava 优先级 - 强制转换和位运算符
【发布时间】:2019-05-15 09:06:10
【问题描述】:

我很难理解一些代码,这些代码展示了如何将 Java 中的 double 转换为 byte[] 的示例,反之亦然。

下面是用于将 double 转换为 byte[] 的代码:

public static byte [] doubleToByteArray (double numDouble)
{
    byte [] arrayByte = new byte [8];
    long numLong;

    // Takes the double and sticks it into a long, without changing it
    numLong = Double.doubleToRawLongBits(numDouble);

    // Then we need to isolate each byte
    // The casting of byte (byte), captures only the 8 rightmost bytes
    arrayByte[0] = (byte)(numLong >>> 56);
    arrayByte[1] = (byte)(numLong >>> 48);
    arrayByte[2] = (byte)(numLong >>> 40);
    arrayByte[3] = (byte)(numLong >>> 32);
    arrayByte[4] = (byte)(numLong >>> 24);
    arrayByte[5] = (byte)(numLong >>> 16);
    arrayByte[6] = (byte)(numLong >>> 8);
    arrayByte[7] = (byte)numLong;

    for (int i = 0; i < arrayByte.length; i++) {
        System.out.println("arrayByte[" + i + "] = " + arrayByte[i]);
    }

    return arrayByte;
}

这是用于将 byte[] 转换回双精度的代码:

public static double byteArrayToDouble (byte [] arrayByte)
{
    double numDouble;
    long numLong;

    // When putting byte into long, java also adds the sign 
    // However, we don't want to put bits that are not from the orignal value
    // 
    // The rightmost bits left unaltered because we "and" them with a 1
    // The left bits become 0 because we "and" them with a 0
    //
    // We are applying a "mask" (& 0x00 ... FFL)
    // 0 & 0 = 0
    // 0 & 1 = 0
    // 1 & 0 = 0
    // 1 & 1 = 1
    //
    // So, the expression will put byte in the long (puts it into the right most position)
    // Then we apply mask to remove the sign applied by java
    // Then we move the byte into its position (shift left 56 bits, then 48 bits, etc.)
    // We end up with 8 longs, that each have a byte set up in the appropriate position
    // By doing an | with each one of them, we combine them all into the orignal long
    //
    // Then we use Double.longBitsToDouble, to convert the long bytes into double.
    numLong = (((long)arrayByte[0] & 0x00000000000000FFL) << 56) | (((long)arrayByte[1] & 0x00000000000000FFL) << 48) |
        (((long)arrayByte[2] & 0x00000000000000FFL) << 40) |    (((long)arrayByte[3] & 0x00000000000000FFL) << 32) |
        (((long)arrayByte[4] & 0x00000000000000FFL) << 24) | (((long)arrayByte[5] & 0x00000000000000FFL) << 16) |
        (((long)arrayByte[6] & 0x00000000000000FFL) <<  8) | ((long)arrayByte[7] & 0x00000000000000FFL);

    numDouble = Double.longBitsToDouble(numLong);

    return numDouble;
}

好的,这是我不太明白的部分。

((long)arrayByte[0] & 0x00000000000000FFL) << 56

看起来好像转换发生在实际的按位运算之前,因为作者是这么说的

表达式会将字节放入长 [...] 然后我们应用掩码删除 java 应用的符号

为什么字节在实际转换之前就被转换成 long 了?操作不应该是这样的吗?

(((long)arrayByte[0]) & 0x00000000000000FFL) << 56

还是有什么我不明白的地方?

【问题讨论】:

    标签: java bit-manipulation operators operator-precedence


    【解决方案1】:

    这是由于运算符优先级和关联性在 Java 中的工作方式。1

    不幸的是,Oracle Java Tutorial 仅提供了部分概述,Java Language Specification 也没有太大帮助,因为它主要通过以下说明将确定运算符优先级的练习留给了读者:

    运算符之间的优先级由语法产生式的层次结构管理。

    一般来说,表达式是从左到右计算的。在运算符优先级方面,下表2适用:

    ╔═══════╦══════════════╦══════════════════════╦═════════════════╗
    ║ Level ║ Operator     ║ Description          ║ Associativity   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 16    ║ []           ║ access array element ║ left to right   ║
    ║       ║ .            ║ access object member ║                 ║
    ║       ║ ()           ║ parentheses          ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 15    ║ ++           ║ unary post-increment ║ not associative ║
    ║       ║ --           ║ unary post-decrement ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 14    ║ ++           ║ unary pre-increment  ║ right to left   ║
    ║       ║ --           ║ unary pre-decrement  ║                 ║
    ║       ║ +            ║ unary plus           ║                 ║
    ║       ║ -            ║ unary minus          ║                 ║
    ║       ║ !            ║ unary logical NOT    ║                 ║
    ║       ║ ~            ║ unary bitwise NOT    ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 13    ║ ()           ║ cast                 ║ right to left   ║
    ║       ║ new          ║ object creation      ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 12    ║ *            ║ multiplicative       ║ left to right   ║
    ║       ║ /            ║                      ║                 ║
    ║       ║ %            ║                      ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 11    ║ + -          ║ additive             ║ left to right   ║
    ║       ║ +            ║ string concatenation ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 10    ║ << >>        ║ shift                ║ left to right   ║
    ║       ║ >>>          ║                      ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 9     ║ < <=         ║ relational           ║ not associative ║
    ║       ║ > >=         ║                      ║                 ║
    ║       ║ instanceof   ║                      ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 8     ║ ==           ║ equality             ║ left to right   ║
    ║       ║ !=           ║                      ║                 ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 7     ║ &            ║ bitwise AND          ║ left to right   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 6     ║ ^            ║ bitwise XOR          ║ left to right   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 5     ║ |            ║ bitwise OR           ║ left to right   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 4     ║ &&           ║ logical AND          ║ left to right   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 3     ║ ||           ║ logical OR           ║ left to right   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 2     ║ ?:           ║ ternary              ║ right to left   ║
    ╠═══════╬══════════════╬══════════════════════╬═════════════════╣
    ║ 1     ║ = += -=      ║ assignment           ║ right to left   ║
    ║       ║ *= /= %=     ║                      ║                 ║
    ║       ║ &= ^= |=     ║                      ║                 ║
    ║       ║ <<= >>= >>>= ║                      ║                 ║
    ╚═══════╩══════════════╩══════════════════════╩═════════════════╝
    

    对于您的具体问题,这意味着不需要在强制转换操作周围放置额外的括号,因为强制转换运算符 () 的优先级高于按位 AND &amp; 运算符(级别 13 与级别7 级)。


    1 我写这篇文章是为了解决有关 Java 中运算符优先级和关联性的问题的规范答案。我找到了很多提供部分信息的现有答案,但我找不到一个概述完整优先级和关联性表的答案。
    2 复制自 @ 的运算符优先级和关联性表987654323@.

    【讨论】:

      猜你喜欢
      • 2016-02-19
      • 2012-09-02
      • 2012-12-13
      • 2017-07-04
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      相关资源
      最近更新 更多