【问题标题】:What if a cast operator is used in shift operators如果在移位运算符中使用强制转换运算符怎么办
【发布时间】:2020-08-18 19:05:13
【问题描述】:

JLS 这么说

移位表达式的类型是左手的提升类型 操作数。

如果左侧操作数的提升类型是 int,那么只有 右手操作数的五个最低位用作移位 距离。就好像右手操作数受到 按位逻辑与运算符 & (§15.22.1) 与掩码值 0x1f (0b11111)。因此,实际使用的移位距离总是在 范围为 0 到 31,包括 0 到 31。

如果左操作数的提升类型是长的,那么只有 右手操作数的六个最低位用作移位 距离。就好像右手操作数受到 按位逻辑与运算符 & (§15.22.1) 与掩码值 0x3f (0b111111)。因此,实际使用的移位距离总是在 范围 0 到 63,包括 0 到 63。

因此,如果我使用 (byte)100<<100(short)100<<100 之类的强制转换运算符明确地创建一个字节和一个短操作数,那么右操作数的可用位是什么?

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

【问题讨论】:

    标签: java casting type-conversion bit-shift jls


    【解决方案1】:

    Java 8 JLS also states in §5.6.1:

    5.6.1。一元数字提升

    一些运算符将一元数字提升应用于单个操作数,该操作数必须产生一个数字类型的值:

    ...

    • 否则,如果操作数的编译时类型为byteshortchar,则通过扩展原语转换(第5.1.2 节)将其提升为int 类型的值。

    ...

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

    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

    所以&lt; int 使用的有效位与int5 位)相同,因为它们会自动向上转换为int

    如果您将整个表达式的结果转换为,例如short (short s = (short) (i &lt;&lt; 2),那么编译器中不会发生自动。但是Bohemian's answer 给出了一个逻辑界限,即右手运算符的哪些位将有效地影响转换后的值。


    在较新的 JLS 版本中,该部分已重新措辞。例如,在Java 14 JLS, §5.6 中我们发现(为简洁起见,该部分被缩短,我建议阅读整段以获得完整的上下文):

    5.6。数值上下文

    数值上下文适用于算术运算符的操作数、数组创建和访问表达式、条件表达式以及 switch 表达式的结果表达式。

    如果表达式是以下之一,则表达式出现在数值算术上下文中:

    ...

    • 移位运算符&lt;&lt;&gt;&gt;&gt;&gt;&gt; 的操作数(第15.19 节)。这些移位运算符的操作数被单独处理,而不是作为一个组处理。 long 移位距离(右操作数)不会将要移位的值(左操作数)提升为 long

    ...

    数字提升确定数字上下文中所有表达式的提升类型。选择提升类型使得每个表达式都可以转换为提升类型,并且在算术运算的情况下,该操作是为提升类型的值定义的。数值上下文中的表达式顺序对于数值提升并不重要。规则如下:

    ...

    1. 接下来,根据以下规则,将加宽基元转换(第 5.1.2 节)和缩小基元转换(第 5.1.3 节)应用于某些表达式:

      ...

      • 否则,所有表达式都不是doublefloatlong 类型。在这种情况下,上下文的类型决定了如何选择提升的类型。

        在数值算术上下文或数值数组上下文中,提升类型为 int,并且任何非 int 类型的表达式都经过扩展原语转换为 int

        在数字选择上下文中,以下规则适用:

        ...

        • 否则,提升的类型为int,所有非int类型的表达式都经过扩展原语转换为int

        ...

    【讨论】:

    • 那么这是否意味着即使我在做(short)100,它实际上也是一个int 100?
    • 这并不试图回答这个问题,它询问“右操作数的可用位是什么”(而不是结果是什么类型)
    • 不,如果你转换了一个变量,这个变量就是转换后的类型。但问题是,转换后的值随后用于二进制数字运算。更准确地说:您发布的带有显式括号的表达式是((short) 100) &lt;&lt; 100。你的意思是(short) (100 &lt;&lt; 100)
    • @Turing85 我得到一个链接,指出它不是二进制数字运算,而是一元运算。 notendur.hi.is/snorri/SDK-docs/lang/….
    • @user12208242 我更新了我的答案并澄清了演员的实际演员。希望这会有所帮助 =) 我还更新了 JLS-Section 以反映 JLS 8 和 JLS 14 中的一元运算符
    【解决方案2】:

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

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

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

    【讨论】:

    • 虽然这在技术上是正确的,但问题中给出的表达式将始终产生 ints,因为类型 &lt; int 已扩大到 ints。
    • @Turing85 这个问题没有问结果类型是什么。该问题询问右操作数的可用位是什么
    • 这并不完全正确。左操作数扩大到int。因此,右操作数受到 int 的限制。
    • @Turing85 右手操作数的类型无关紧要。这是关于使用了该操作数的多少位。
    • ... 而这 - 作为回报 - 取决于 left 操作数的类型,它被提升为int
    猜你喜欢
    • 1970-01-01
    • 2020-03-03
    • 2019-07-26
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多