所以我遇到了关于按位运算符和位移的奇怪行为。我试图通过使用位掩码来更快地做一个小检查,我来到这里:
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;
}
}
a
,b
,c
和h
不会出现编译错误;但是d
,e
,f
和g
会这样做。编译器要求显式转换为byte
或将最后一个变量声明为int
。我注意到bitwize &
和|
也有类似的行为。
有人可以解释这里发生了什么吗?
编译器为a
,b
,c
和h
工作的工作原理是什么?
编辑:或者这不完全重复
我认为这个问题是不同的,因为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带来更多有趣的信息。
答案 0 :(得分:3)
编译器知道final
值或literal
无法更改,并且可以安全地隐式cast
constant
和3
到byte
使用给定的值。
非终结价值不能以同样的方式推理。
明确比隐含更好。
这就是为什么我讨厌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;