我知道在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中字节的有效值为-128127。因此,超出该范围的任何值都不能仅视为byte,而需要进行显式转换。因此,示例1和示例2通过了。

有损缩小转换
为了理解其余部分为什么失败,我们必须研究Java语言规范(JLS),更具体地说是5.1.3. Narrowing Primitive Conversion5.2. Assignment Contexts一章。
它说从intbyte的转换(如果它不在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/

10-12 14:28
查看更多