Java 优先级 - 转换和按位运算符
Java Precedence - Casting and Bitwise Operators
我很难理解一些代码,这些代码显示了 Java 中的双精度如何转换为 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
似乎转换发生在实际的按位运算之前,因为作者说
the expression will put byte in the long [...] Then we apply mask to remove the sign applied by java
为什么字节在实际转换之前就被转换成 long?操作不应该像这样吗?
(((long)arrayByte[0]) & 0x00000000000000FFL) << 56
或者还有什么不明白的地方?
这是由于运算符优先级和结合性在 Java 中的工作方式。1
不幸的是,Oracle Java Tutorial provides only a partial overview, and the Java Language Specification 也没有太大帮助,因为它主要将计算运算符优先级的练习留给了 reader,方法是:
Precedence among operators is managed by a hierarchy of grammar productions.
一般来说,表达式是从左到右求值的。在运算符优先级方面,以下 table2 适用:
╔═══════╦══════════════╦══════════════════════╦═════════════════╗
║ 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 ║
║ ║ *= /= %= ║ ║ ║
║ ║ &= ^= |= ║ ║ ║
║ ║ <<= >>= >>>= ║ ║ ║
╚═══════╩══════════════╩══════════════════════╩═════════════════╝
对于您的具体问题,这意味着不需要在强制转换运算符周围放置额外的括号,因为强制转换运算符 ()
的优先级高于按位与 &
的优先级运算符(13 级与 7 级)。
1 我写这篇文章是为了解决有关 Java 中运算符优先级和结合性的问题的规范答案。我找到了很多提供部分信息的现有答案,但我找不到一个给出完整优先级和结合性概述的答案 table。
2 运算符优先级和关联性 table 转载自 https://introcs.cs.princeton.edu/java/11precedence/。
我很难理解一些代码,这些代码显示了 Java 中的双精度如何转换为 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
似乎转换发生在实际的按位运算之前,因为作者说
the expression will put byte in the long [...] Then we apply mask to remove the sign applied by java
为什么字节在实际转换之前就被转换成 long?操作不应该像这样吗?
(((long)arrayByte[0]) & 0x00000000000000FFL) << 56
或者还有什么不明白的地方?
这是由于运算符优先级和结合性在 Java 中的工作方式。1
不幸的是,Oracle Java Tutorial provides only a partial overview, and the Java Language Specification 也没有太大帮助,因为它主要将计算运算符优先级的练习留给了 reader,方法是:
Precedence among operators is managed by a hierarchy of grammar productions.
一般来说,表达式是从左到右求值的。在运算符优先级方面,以下 table2 适用:
╔═══════╦══════════════╦══════════════════════╦═════════════════╗
║ 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 ║
║ ║ *= /= %= ║ ║ ║
║ ║ &= ^= |= ║ ║ ║
║ ║ <<= >>= >>>= ║ ║ ║
╚═══════╩══════════════╩══════════════════════╩═════════════════╝
对于您的具体问题,这意味着不需要在强制转换运算符周围放置额外的括号,因为强制转换运算符 ()
的优先级高于按位与 &
的优先级运算符(13 级与 7 级)。
1 我写这篇文章是为了解决有关 Java 中运算符优先级和结合性的问题的规范答案。我找到了很多提供部分信息的现有答案,但我找不到一个给出完整优先级和结合性概述的答案 table。
2 运算符优先级和关联性 table 转载自 https://introcs.cs.princeton.edu/java/11precedence/。