谜题14:转义字符的溃败 摘自《java解惑》一书,下载地址:http://download.csdn.net/detail/itismelzp/9407769 下面的程序使用了两个Unicode 的转义字符,它们是用其十六进制代码来表示 Unicode 字符。那么,这个程序会打印什么呢? public class EscapeRout
谜题9:半斤 摘自《java解惑》一书,下载地址:http://download.csdn.net/detail/itismelzp/9407769 现在该轮到你来写些代码了,好消息是,你只需为这个谜题编写两行代码,并为下一个谜题也编写两行代码。这有什么难的呢?我们给出一个对变量x 和i 的声明即可,它肯定是一个合法的语句: x += i;但是,它并不是: x = x + i; 许多程序员都会认为该迷题中的第一个表达式(x += i)只是第二个表达式(x =x + i)的简写方式。但是这并不十分准确。这两个表达式都被称为赋值表达式。 第二条语句使用的是简单赋值操作符(=),而第一条语句使用的是复合赋值操作符。(复合赋值操作符包括 +=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、^=和|=)Java 语言规范中讲到,复合赋值 E1 op= E2 等价于简单赋值E1 =(T)((E1)op(E2)),其中T 是E1 的类型,除非E1 只被计算一次。 换句话说,复合赋值表达式自动地将它们所执行的计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,那么这个转型不会造成任何影响。然而,如果结果的类型比该变量的类型要宽,那么复合赋值操作符将悄悄地执行一个窄化原始类型转换。因此,我们有很好的理由去解释为什么在尝试着执行等价的简单赋值可能会产生一个编译错误。 为了说得具体一些,并提供一个解决方案谜题16:行打印程序 行分隔符(line separator)是为用来分隔文本行的字符或字符组合而起的名字,并且它在不同的平台上是存在差异的。在Windows 平台上,它是CR 字符(回车)和紧随其后的LF 字符(换行)组成的,而在UNIX 平台上,通常单独的LF 字符被当作换给这个谜题,假设我们在该谜题的两个赋值表达式之前有下面这些声明: short x = 0;int i = 123456;复合赋值编译将不会产生任何错误: x += i; // 包含了一个隐藏的转型!你可能期望x 的值在这条语句执行之后是123,456,但是并非如此l,它的值是-7,616。int 类型的数值123456 对于short 来说太大了。自动产生的转型悄悄地把int 数值的高两位给截掉了。这也许就不是你想要的了。相对应的简单赋值是非法的,因为它试图将int 数值赋值给short 变量,它需要一个显式的转型: x = x + i; // 不要编译——“可能会丢掉精度” 这应该是明显的,复合赋值表达式可能是很危险的。为了避免这种令人不快的突袭,请不要将复合赋值操作符作用于byte、short 或char 类型的变量上。在将复合赋值操作符作用于int类型的变量上时,要确保表达式右侧不是long、float或double 类型。在将复合赋值操作符作用于float 类型的变量上时,要确保表达式右侧不是double 类型。这些规则足以防止编译器产生危险的窄化转型。 总之,复合赋值操作符会悄悄地产生一个转型。如果计算结果的类型宽于变量的类型,那么所产生的转型就是一个危险的窄化转型。这样的转型可能会悄悄地丢弃掉精度或数量值。对语言设计者来说,也许让复合赋值操作符产生一个不可见的转型本身就是一个错误;对于在复合赋值中的变量类型比计算结果窄的情况,也许应该让其非法才对。