如果在移位运算符中使用强制转换运算符会怎样

What if a cast operator is used in shift operators

JLS 表示

The type of the shift expression is the promoted type of the left-hand operand.

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.

因此,如果我使用 (byte)100<<100(short)100<<100 等强制转换运算符显式创建一个字节和一个短操作数,右操作数的可用位是多少?

编辑:如果操作数已经使用转换运算符转换为不同的(更小的)类型,它是否会进行数字提升(unary/binary)?如果是这种情况,您将如何解释具有字节变量的表达式 b1 = (byte)(b2 + b3) 因为在强制转换之后,字节结果可能会根据数字提升转换为 int?

最大可用移位距离的位数由 log2n 给出,其中 n 是用于表示左手类型值的位数。

byte 有 8 位。 log28 是 3。因此只使用最右边的 3 位,给出 0-7 范围内的移位值。

short 有 16 位。 log216 是 4。因此只使用最右边的 4 位,给出 0-15 范围内的移位值。

Java 8 JLS also states in §5.6.1:

5.6.1. Unary Numeric Promotion

Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:

...

  • Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).

...

因此,如果我们采用以下表达式:

int i = ...
short s = (short) i << 2;

会导致编译错误:

Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i << 2;

Ideone demo

这是因为强制转换绑定到移位的第一个参数,而不是整个表达式。这是带有显式括号的整个表达式:

short s = ((byte) i) << 2;

int i = ...;
int j = (short) i << 2;

将成功编译。

Ideone demo

因此,用于任何内容的有效位 < intint 相同(5 位),因为它们会自动升级为 int

如果将整个表达式的结果转换为,例如shortshort s = (short) (i << 2),则编译器中不会发生自动操作。但是 给出了一个逻辑界限,说明右手运算符的哪些位将有效地影响后面的值投.


在较新的 JLS 版本中,该部分已改写。例如,在 Java 14 JLS, §5.6 中我们发现(为简洁起见,该部分已缩短,我建议阅读整个段落以了解完整的上下文):

5.6. Numeric Contexts

Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions of switch expressions.

An expression appears in a numeric arithmetic context if the expression is one of the following:

...

  • An operand of a shift operator <<, >>, or >>> (§15.19). Operands of these shift operators are treated separately rather than as a group. A long shift distance (right operand) does not promote the value being shifted (left operand) to long.

...

Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:

...

  1. Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:

    ...

    • Otherwise, none of the expressions are of type double, float, or long. In this case, the kind of context determines how the promoted type is chosen.

      In a numeric arithmetic context or a numeric array context, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.

      In a numeric choice context, the following rules apply:

      ...

      • Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.

      ...