Java中的原始强制转换和赋值

Ale*_*lex 45 java

我理解为什么以下是错误的:

byte a = 3; 
byte b = 8; 
byte c = a + b;  // compile error
Run Code Online (Sandbox Code Playgroud)

它不会编译.表达式总是导致int.所以我们应该做了明确的演员:

byte c = (byte) (a + b);   // valid code
Run Code Online (Sandbox Code Playgroud)

我不明白为什么以下是正确的:

byte d = 3 + 8;   // it's valid! why?
Run Code Online (Sandbox Code Playgroud)

因为字面整数(例如3或8)总是隐式的int.并且int-or-smaller表达式也总是导致int.谁能解释一下这里发生了什么?

我唯一可以猜到的是编译器将此表达式等同于以下内容:

byte d = 11;
Run Code Online (Sandbox Code Playgroud)

并不认为这是一个表达.

jas*_*son 46

这有少†做与否3 + 8进行评估,以11在编译时间,要与事实的编译器是明确允许隐式窄ints到byteS IN某些情况下.特别是,语言规范明确允许隐式缩小转换为可以适合编译时byte的类型的常量表达式.intbyte

JLS的相关部分是第2.2节:

此外,如果表达式类型的常量表达式(§15.28) ,byte,short, charint:

  • 如果变量的类型是byte,, short或者char,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示.

常量的编译时缩小意味着byte theAnswer = 42; 允许代码如: .如果没有缩小,整数文字42具有类型的事实int将意味着需要强制转换byte:

†:显然,根据规范,需要对常量表达式进行求值,以确定它是否适合较窄的类型.但重点是,如果没有规范的这一部分,编译器将不允许进行隐式缩小转换.

我们在这里说清楚:

byte a = 3; 
byte b = 8; 
Run Code Online (Sandbox Code Playgroud)

允许这些的原因是由于规范的上述部分.也就是说,允许编译器将文字的隐式缩小转换3为a byte.这不是因为编译器在编译时将常量表达式计算3为其值3.

  • 虽然您的答案非常有用,但它似乎专门用于取消现有的其他答案.理想情况下,他们只会相互支持,一个是示例,另一个是JLS引用.我试图保持我的downvotes建设性,但在这种情况下,我只是发现语气非常分散注意力,所以我觉得没有评论投票是一个很好的妥协. (2认同)

fge*_*fge 41

我唯一可以猜到的是编译器将此表达式等同于以下内容:

是的,它确实.只要右侧表达式由常量组成(符合所需的基本类型 - 请参阅@Jason对JLS所说的内容的答案),您就可以做到这一点.这将无法编译,因为128超出范围:

byte a = 128;
Run Code Online (Sandbox Code Playgroud)

请注意,如果您将第一个代码段转换为:

final byte a = 3; 
final byte b = 8; 
byte c = a + b;
Run Code Online (Sandbox Code Playgroud)

它汇编!由于你的两个字节是final 并且它们的表达式是常量,这次,编译器可以确定结果在首次初始化时适合一个字节.

但是,这不会编译:

final byte a = 127; // Byte.MAX_VALUE
final byte b = 1;
byte c = a + b // Nope...
Run Code Online (Sandbox Code Playgroud)

编译器将出现"可能的精度损失"错误.

  • @Jason你错过了"_并且常量表达式的值可以在变量的类型中表示."因此3 + 8的计算结果与11相关,而不是128. (2认同)
  • @Jason你能否具体引用这个答案中不正确的部分?我跟着你有困难."只要右侧表达式由常数构成"似乎与您的JLS引文一致. (2认同)