我知道在Java中,整数默认是int,所以如果我写这样的话
byte byteValue = 2;
Java自动将文字值 2 (默认为int)转换为字节。如果我写同样的东西
byte byteValue = 4/2;
RHS被评估为一个int值,并隐式转换为一个字节。但是,在以下两种情况下为什么不进行隐式转换?
int n1 = 4;
byte value = n1/2;
或者在这个byte n1 = 4;
byte value = n1/2;
我知道这两个示例的RHS都被评估为int。但是Java为什么不像前两种情况那样将其隐式转换为字节,仅当有文字时才隐式转换为较小的数据类型? 最佳答案
说明
让我们看一下您的代码和一些修改后的示例:
// Example 1
byte byteValue = 2;
// Example 2
byte byteValue = 4/2;
// Example 3
byte byteValue = 2000;
// Example 4
byte byteValue = 500/2;
// Example 5
int n1 = 4;
byte byteValue = n1/2;
无损转换
您将获得示例3,示例4和示例5的提及的编译时错误。
首先,示例1至4的简单数学运算是在编译时执行的。因此,Java将在编译时计算
500 / 2
,并使用byte byteValue = 250;
基本上替换该代码。Java中字节的有效值为
-128
到127
。因此,超出该范围的任何值都不能仅视为byte
,而需要进行显式转换。因此,示例1和示例2通过了。有损缩小转换
为了理解其余部分为什么失败,我们必须研究Java语言规范(JLS),更具体地说是5.1.3. Narrowing Primitive Conversion和5.2. Assignment Contexts一章。
它说从
int
到byte
的转换(如果它不在byte
的范围内)是缩小了原始转换,并且它可能会丢失信息(出于明显的原因)。继续说明转换是如何完成的:从第二章开始,如果值是常数表达式,则允许进行窄转换的分配。
简而言之,必须向Java明确声明可能会丢失信息(因为值超出范围)的缩小转换。 Java不仅会在不强制您的情况下为您完成任务。这是通过 Actor 阵容完成的。
所以举个例子
byte byteValue = (byte) (500 / 2);
产生值-6
。常数表达
您的最后一个示例非常有趣:
int n1 = 4;
byte byteValue = n1/2;
尽管不超出范围,但Java仍将其视为有损缩小转换。为什么会这样?好吧,Java无法保证
n1
在执行n1/2
之前的第二秒内没有更改。因此,它必须考虑所有代码,以查看是否有人偷偷地访问了n1
并对其进行了更改。 Java在编译时不进行这种分析。因此,如果您可以告诉Java
n1
保持4
且实际上永远不会改变,那么它将可以编译。在这种特定情况下,将其设置为final
就足够了。所以用final int n1 = 4;
byte byteValue = n1/2;
它实际上将进行编译,因为Java知道n1
保留为4
并且无法再更改。因此,它可以在编译时将n1/2
计算为2
,并将代码替换为基本上在范围内的byte byteValue = 2;
。因此,如前面在5.2. Assignment Contexts中所述,您将
n1 / 2
设为常数表达式。您可以检查详细信息,以便在15.29. Constant Expressions中具有常量表达式。基本上,所有简单的事情都可以轻松地就地计算,而无需任何方法调用或其他花哨的东西。
关于java - Java中的隐式转换如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62965817/