有趣的行为返回Java中的按位运算符和位移的值

时间:2014-02-10 06:28:01

标签: java bitwise-operators

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

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 &|也有类似的行为。

有人可以解释这里发生了什么吗? 编译器为abch工作的工作原理是什么?

编辑:或者这不完全重复

我认为这个问题是不同的,因为Why can not I add two bytes and get an int and I can add two final bytes get a byte?因为引起有趣行为的原因是编译器如何优化bitwize移位操作。

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

2 个答案:

答案 0 :(得分:3)

简答:

编译器知道final值或literal无法更改,并且可以安全地隐式cast constant3byte使用给定的值。

非终结价值不能以同样的方式推理。

  

明确比隐含更好。

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

练习:

constant或文字3更改为byte不适合的内容并查看其抱怨方式

答案 1 :(得分:3)

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

byte的推广类型是int - 这就是为什么在大多数情况下你必须按如下方式投射结果的原因:

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

所以真正的问题是为什么在前三行中不需要铸造。现在,如果你改变了这条线,那就不准确了:

private final static int constant = 3;

为:

private final static int constant = 1000;

您将收到编译错误:

byte c = 0b1 << constant;

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

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

byte c = 0b1 << 3;