JLS说
移位表达式的类型是左手边的提升类型操作数。
如果左侧操作数的提升类型为int,则只有右侧操作数的五个最低阶位用作移位距离就好像右侧操作数受到逐位逻辑AND运算符&(§15.22.1),掩码值为0x1f(0b11111)。因此,实际使用的换档距离始终在范围0到31,包括0到31。
如果左侧操作数的提升类型较长,则只有右侧操作数的六个最低阶位用作移位距离就好像右侧操作数受到逐位逻辑AND运算符&(§15.22.1),掩码值为0x3f(0b111111)。因此,实际使用的换档距离始终为范围0到63,包括0到63。
因此,如果我使用像(byte)100<<100
和(short)100<<100
这样的强制转换运算符显式生成一个字节和一个短操作数,那么右操作数的可用位是多少?
编辑:如果已使用强制转换运算符将操作数转换为其他(较小)类型,则操作数是否会进行数字提升(一元/二进制)?如果是这种情况,您将如何解释具有字节变量b1 = (byte)(b2 + b3)
的表达式,因为在强制转换后,字节结果可能会根据数字提升转换为int?
Java 8 JLS也在§5.6.:中进行了说明
一次数字促销
某些运算符将一元数字提升应用于单个操作数,该操作数必须生成数字类型的值:
- 否则,如果操作数的编译时类型为
byte
、short
或char
,则会通过加宽基元转换将其提升为int
类型的值(§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演示
这是由于强制转换绑定到shift的第一个参数,而不是整个表达式。以下是带有显式括号的整个表达式:
short s = ((byte) i) << 2;
而
int i = ...;
int j = (short) i << 2;
将成功编译。
Ideone演示
因此,用于任何< int
的有效比特与用于int
的有效比特(5
比特)相同,因为它们被自动上广播到int
。
如果将整个表达式的结果强制转换为,例如short
(short s = (short) (i << 2)
),则编译器中不会发生自动操作。但是Bohemian的答案给出了一个逻辑界限,即右手运算符的哪些位将有效地影响强制转换后的值。
在较新的JLS版本中,该部分已重新编写。例如,在Java 14 JLS的§5.6中,我们发现(该部分因简短而缩短,我建议阅读整个段落以获得完整的上下文):
5.6.数字上下文
数值上下文适用于算术运算符的操作数、数组创建和访问表达式、条件表达式以及开关表达式的结果表达式。
如果表达式是以下表达式之一,则该表达式将出现在数字算术上下文中:
- 移位运算符
<<
、>>
或>>>
的操作数(§15.19)。这些移位运算符的操作数被单独处理,而不是作为一组处理。long
移位距离(右操作数)不会将要移位的值(左操作数)提升为long
。。。
数值提升确定数值上下文中所有表达式的提升类型。升级类型的选择使得每个表达式都可以转换为升级类型,并且在算术运算的情况下,该运算是为升级类型的值定义的。数值上下文中表达式的顺序对于数值提升来说并不重要。规则如下:
接下来,根据以下规则,将加宽基元转换(§5.1.2)和变窄基元转化(§5.1.3)应用于一些表达式:
否则,所有表达式都不是
double
、float
或long
类型。在这种情况下,上下文的类型决定了如何选择提升的类型。在数值算术上下文或数值数组上下文中,提升的类型为
int
,并且任何非int类型的表达式都将经历扩展基元转换为int
在数字选择上下文中,以下规则适用:
- 否则,提升的类型为
int
,并且所有不属于int
类型的表达式都将经历扩展原语转换为int
。。。
最大可用移位距离的位数由log2n给出,其中n是用于表示左手类型值的位数。
CCD_ 27具有8个比特。log28为3。因此,只使用最右边的3位,给出0-7范围内的移位值。
CCD_ 28具有16个比特。log216为4。因此,只使用最右边的4位,给出0-15范围内的移位值。