【问题标题】:Interesting behaviour return values of bitwise operators and bit shift in Java [duplicate]Java中按位运算符和位移的有趣行为返回值[重复]
【发布时间】:2014-03-07 09:12:09
【问题描述】:

所以我遇到了关于按位运算符和位移的奇怪行为。我试图通过使用位掩码更快地进行小检查,但遇到了这个问题:

public class Weirdness {

    private final static int constant = 3;

    private static int notConstant = 3;

    public void stuff() {
        byte a = 0b1 << 3;
        byte b = 0b1 << (int) 3;
        byte c = 0b1 << constant;
        byte d = 0b1 << notConstant; //error
        byte e = 0b1 << getAnInt(); //error
        byte f = 0b1 << getAFinalInt(); //error
        int i = 3;
        byte g = 0b1 << i; //error
        final int j = 3;
        byte h = 0b1 << j;
    }

    public static int getAnInt() {
        return 3;
    }

    public static final int getAFinalInt() {
        return 3;
    }

}

abch不给出编译错误;但是defg 可以。编译器要求显式转换为byte 或将最后一个变量声明为int。我也注意到 bitwize &amp;| 的类似行为。

有人能解释一下这里发生了什么吗? 为abch 工作的编译器有什么魔力?

编辑:或者这不完全是重复的

我相信这个问题与Why can not I add two bytes and get an int and I can add two final bytes get a byte? 不同,因为导致有趣行为的是编译器如何优化按位移位操作。

而且由于我寻求一个理论上的答案(因为我已经明白我可以通过强制转换来编译我的代码)移位和其他 bitwize 操作如何确定它们的返回值,我相信这个问题可以补充 Java - bit shifting with integers and bytes 并带来更多StackOverflow 的有趣信息。

【问题讨论】:

  • Rohit 的答案是我认为的你正在寻找的东西

标签: java bitwise-operators


【解决方案1】:

From JLS:移位表达式的类型是左侧操作数的提升类型。

byte 的提升类型是 int - 这就是为什么在大多数情况下,您必须将结果转换如下:

byte e = (byte) (0b1 << getAnInt()); 

所以真正的问题是为什么在前 3 行中不需要强制转换。现在,这也不准确,因为如果您要更改线路:

private final static int constant = 3;

到:

private final static int constant = 1000;

你会得到一个编译错误:

byte c = 0b1 << constant;

也是。

移位操作可能会创建一个整数,其值大于赋值左侧的字节可以容纳的值 - 这会触发编译时错误并迫使我们强制转换为字节以便仅获取最不重要的字节8 位。

那么为什么在前 3 行中我们不需要强制转换为字节?
编译器识别出我们正在使用一个常量(或一个final),因此“知道”这个值以后不能更改,因此它允许Narrowing Primitive Conversion 分配给左侧的字节-:

byte c = 0b1 << 3;

【讨论】:

  • 哇!谢谢!所以这基本上是我没有错误的情况,实际上是异常,而不是相反。很好的答案。
【解决方案2】:

简答:

编译器知道final 值或literal 不能更改,并且可以安全地将cast constant3 隐式转换为具有给定值的byte

不能以同样的方式推断非最终值。

显式优于隐式。

这是我讨厌 implicit 任何与编写程序有关的事情的一个例子。

运动:

constant 或文字3 更改为不适合byte 的内容,看看它是如何抱怨的

【讨论】:

  • 如果我没记错的话,Java 都是按值传递的。那么为什么它不适用于ef?因为它适用于c。我认为 Java 可以遍历这些引用并进行优化。
  • 这与pass by value 或其他类似的东西无关,Java 通过值传递references。一个函数可以返回 anything, final 在一个函数上只是意味着它不能被覆盖,它没有说明它的返回值。 Final Word on Final
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-03-19
  • 2011-04-19
  • 2013-01-25
  • 2015-03-19
相关资源
最近更新 更多