缩小原语转换期间的Java编译器行为
K.Sierra和B.Bates在他们的书《SCJP学习指南》中写道 以下是合法的缩小原语转换期间的Java编译器行为,java,compiler-construction,casting,primitive,scjp,Java,Compiler Construction,Casting,Primitive,Scjp,K.Sierra和B.Bates在他们的书《SCJP学习指南》中写道 以下是合法的字节b=27;,但这仅仅是因为编译器自动将文本值缩小为一个字节。换句话说,编译器放入强制转换。前面的代码与下面的代码相同:字节b=(字节)27; 我认为这个解释是不正确的这两行代码相同吗? 其实 byte b = 27; 它只是一个常数。编译时常数的缩小是该代码有效的唯一原因。所以不需要石膏。缩小范围时,编译器只检查指定的值是否适合变量的类型。 报告说: 如果变量的类型是byte、short或char,并且常量表
字节b=27;
,但这仅仅是因为编译器自动将文本值缩小为一个字节。换句话说,编译器放入强制转换。前面的代码与下面的代码相同:字节b=(字节)27;
我认为这个解释是不正确的这两行代码相同吗?
其实
byte b = 27;
它只是一个常数。编译时常数的缩小是该代码有效的唯一原因。所以不需要石膏。缩小范围时,编译器只检查指定的值是否适合变量的类型。
报告说:
如果变量的类型是byte、short或char,并且常量表达式的值可以在变量的类型中表示,则可以使用窄化原语转换
在第二种情况下
byte b = (byte) 27;
在运行时进行强制转换,并且根据特定规则计算原语值。编译器不关心基元类型的兼容性。比如说
byte b = 5.0; // compile error
byte b = 277777777; // compile error
byte b = (byte) 5.0; // valid!
byte b = (byte) 277777777; // valid!!
这让我觉得加宽/变窄转换和铸造是根本不同的。但在各种来源中,它们经常互换使用。这是正确的吗?如果出现隐式变窄转换,是否在封盖下进行铸造
有人能解释一下在上述书中描述的情况下编译器的真实行为吗?测试它很容易。将以下内容放入Temp.java中:
class Temp {
public static void main(String[] argv) {
byte b = 27;
System.out.println(b);
}
}
现在用您最喜欢的编译器编译它:
$ javac Temp.java
现在用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
}
$javap-c临时类
从“Temp.java”编译而来
班级临时工{
温度();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:bipush 27
2:istore_1
3:getstatic#2//Field java/lang/System.out:Ljava/io/PrintStream;
6:iload_1
7:invokevirtual#3//方法java/io/PrintStream.println:(I)V
10:返回
}
现在将27
替换为(字节)27
,然后再次运行。你会发现没有区别。事实上,这两个类文件将具有相同的md5sum
字节码中没有运行时强制转换,因为编译器认为不需要它,并对它进行了优化
我相信你是对的,行
字节b=27
在语法上不同于行字节b=(字节)27
,但它们在语义上是相同的,因为所有标准编译器都足够聪明,可以将行优化为单个字节码 在开始之前,需要注意的是,在java中,所有纯数字文本都是int
值
关于允许的非强制转换常量的关键短语可以用变量的类型表示。这只意味着变量类型的常量“在范围内”,因此:
- 对于
-128到127字节
- 对于
-32768到32767short
- 对于
0到65535char
byte b = nnn & 0xFF;
如果nnn在范围内,则掩码不会更改值,因此不会丢失任何内容,因此没有问题-编译正常
如果nnn超出范围,信息将丢失,因此需要显式强制转换来确认丢失
如果您还记得所有整数文本都是int,那么这些规则实际上与将int赋值给更窄的变量类型的规则没有什么不同,除非编译器知道值将“适合”,则不允许强制转换,可能重复的