缩小基元转换期间的Java编译器行为

kap*_*and 4 java compiler-construction primitive casting scjp

K.Sierra和B.Bates在他们的着作"SCJP学习指南"中写道

" 以下是合法的,byte b = 27;但仅仅是因为编译器自动将文字值缩小为一个字节.换句话说,编译器放入强制转换.前面的代码与以下代码相同:byte b = (byte) 27; "

在我看来,这种解释是不正确的.这两行代码是否相同?

事实上

byte b = 27;
Run Code Online (Sandbox Code Playgroud)

只是一个常数.并且编译时缩小常量是此代码有效的唯一原因.所以不需要演员阵容.缩小编译器时,只需检查指定的值是否适合变量的类型.该规范说:

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

在第二种情况下

byte b = (byte) 27;
Run Code Online (Sandbox Code Playgroud)

在运行期间确实发生了转换,并且根据特定规则计算原始值.编译器不关心基元类型的兼容性.例如

byte b = 5.0; // compile error
byte b = 277777777; // compile error
byte b = (byte) 5.0; // valid!
byte b = (byte) 277777777; // valid!!
Run Code Online (Sandbox Code Playgroud)

这让我觉得扩大/缩小转换和铸造是根本不同的.但在各种来源中,它们经常互换使用.它是否正确?如果隐式缩小转换,是否会在封面下进行铸造?

任何人都能解释上述书中描述的情况下编译器的真实行为吗?

Ada*_*iss 5

测试它很容易.将以下内容放在Temp.java中:

class Temp {
  public static void main(String[] argv) {
    byte b = 27;
    System.out.println(b);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在用您喜欢的编译器编译它:

$ javac Temp.java
Run Code Online (Sandbox Code Playgroud)

现在用javap转储字节码:

 $ javap -c Temp.class
 Compiled from "Temp.java"
  class Temp {
    Temp();                                                                                                                             
      Code:
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

    public static void main(java.lang.String[]);                                                                                        
      Code:
         0: bipush        27
         2: istore_1
         3: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;                                       
         6: iload_1
         7: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        10: return
  }
Run Code Online (Sandbox Code Playgroud)

现在更换27(byte)27,然后再次运行.你会发现没有区别.事实上,这两个类文件将具有相同的md5sum.

字节码中没有运行时强制转换,因为编译器发现它不需要,并对其进行了优化.

我相信你的语法线条byte b = 27与行不同是正确的byte b = (byte) 27,但它们在语义上是相同的,因为所有标准编译器都足够聪明,可以将行优化为单个字节码.