我对此代码段有 2 个问题
- 方法 1 工作正常,方法 2 不行。这是什么原因?
- 在方法 1 中,返回值为字节(8 位)。但我们实际上返回了一个 char 值(16 位)。这里实际发生了什么?
//方法一
static byte m1() {
final char c = 'b'-'a';
return c;
}
//方法二
static byte m3(final char c) {
return c; // 3
}
char
在 Java 中是16 位无符号值,byte
而是8 位有符号值。字节的允许范围是[-128, 127]
。因此,并非所有字符都可以在byte
.
在您的第一种方法中,您将返回一个char
代码点 = 1 ( 'b' - 'a'
)。现在既然你已经定义了char
asfinal
并为其分配一个常量表达式,因此它成为编译时常量。因此,编译器不会给出任何编译器错误。
如果表达式是 byte、short、char 或 int 类型的常量表达式(第 15.28 节): - 如果变量的类型是 byte、short 或 char,并且常量的值,
则可以使用缩小原语转换表达式可以用变量的类型来表示。
强调我的。
但是,如果你做c
非最终的,它也会导致编译器错误:
static byte m1() { // This will be an error
char c = 'b'-'a';
return c;
}
原因是,c
不再是编译时间常量,并且编译器不会进行隐式向下转换。
在第二种方法中,您将返回char
您通过的。那里的参数c
没有编译时间常数。在编译时不知道该方法可能获得什么值。就像,如果您传递的char
代码点不在允许的byte
值范围内,它将不起作用。
要使第二种方法起作用,您可以进行显式转换:
static byte m3(final char c) {
return (byte)c; // 3
}
在m1()
编译器中,char c
它的值是常量,1
因此不会抱怨,因为它知道它可以放入字节中。如果您将其更改为final char c = 128
127 是byte
您将收到投诉的最大大小,就像您final
从char c
.
在方法 2 中,编译器不能进行从 chat 到 byte 的窄化隐式强制转换,因为它可能会导致精度损失(Java 支持 Unicode 字符,并且它的 char 原始类型定义为 16 位信息的大小,不同来自通常为 8 位的 C 语言)
但是在方法 1 中,编译器可以确定常量值 'b'-'a' 实际上不会导致精度损失,因此允许您执行隐式转换。
看看:http ://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
现在原因m1()
有效而m3()
无效是因为在m1()
c 中是 a compile-time constant
。
分析这段代码:
byte b = 'x'; //compile-time constant
int i = 'x'; //compile-time constant
char c = 'x'; //compile-time constant
c = i; //compilation error
c = b; //compilation error
b = i; //compilation error
b = c; //compilation error
i = b; // Okay
i = c; // Okay
对于运行时变量,编译器不会执行可能导致数据丢失的隐式转换。