以下内容全部来自《java解惑》
1、奇数性
这个谜题主要是提醒我们要注意如何来判断一个数是不是奇数
比如:
i % 2 == 1
这个是否可以成功判断?
如果i是负数呢?显然会是-1
所以我更喜欢:i % 2 != 0
还有一种看起来比较high的:i&1 != 0
2、找零时刻
这个谜题是货币计算的,由于浮点数在计算机中并不会精确保存,所以,有时候难免有误差,因此问题也就产生了
如:System.out.println(2.00-1.10);
输出的不是你想象的0.90,而是一个近似值0.8999999999999999
操作这些需要很精确的数据时我们最好采用BigDecimal数据类型。
BigDecimal类型定义了add,subtract,multiply,divide方法来进行精确的四则计算。
如上例:
System.out.println(BigDecimal("2.00").subtract(BigDecimal("1.10')));
这样就OK了
所得提示:在需要精确的地方,要避免使用float ,double,对于货币,要使用int,long,BigDecimal。
3、长整除
这个谜题是关于long和int的混合计算的
如:long tmp = 24*23*34*4*5000000;
以及long tmp= 1L * 24*23*34*4*5000000;
这两个表达式的tmp一样吗?相信你知道了吧!
提示:操作大数据时,千万要提防溢出!
4、初级问题
System.out.println(12345+5432l);
等于多少?是66666?
注意l和1的区别,其实这道题是在提示我们,当要表示长整型时要用L,而不是l
5、十六进制的趣事
System.out.println(Long.toHexString(0x100000000L + 0xcafebabe))
会输出多少呢?cafebabe
为什么呢?
十进制可以清楚的表示一个负数,而对于八进制或者十六进制而言,负数的表示不那么清楚,比如上面的0xcafebabe是正数还是负数呢?
我们需要知道内存里面存的时候怎么表示正负数:如果十六进制和八进制字面常量的最高位被置位了,那么它们就表示负数。因此0xcafebabe是负数。
其次我们还需要知道:符号扩展,因为第一个操作数是long型,所以int应该进行扩展,而由于int是有符号的,所以要进行有符号扩展,即是负数的话,前面的扩展位都是1
因此就有了下面的计算:
0xffffffffcafebabe
+ 0x0000000100000000
= 0x00000000cafebabe
提示:
1、对于十六进制或八进制运算,要注意符号位
2、扩展类型的时候注意是不是有符号扩展
3、运算时,最好避免两个不一样类型的数据进行运算
6、多重转型
System.out.println((int)(char)(byte)-1);
输出什么?65535
int->byte:转换的时候直接截取第八位即可,依然是-1
byte->char:它们不能直接转,因为byte有符号而char是无符号的,可以化成两个动作,byte->int->char,byte->int,有符号扩展(-1),int->char,直接截取低十六位为0xFFFF(0xFFFFFFFF),即65535。
char->int:直接补零,还是原数值。依然是65535.
提示:如果最初的数值有符号,那么就执行符号扩展,如果它是char,那么不管它将被转换成什么类型,都执行零扩展。
7、互换内容
int x = 1984;//0x7c0
int y = 2001;//0x7d1
x^=y^=x^=y;
System.out.println("x="+x+";y="+y);
打印多少?x=0;y=1984
这个就是告诉我们,不可再单个表达式里对相同对象赋值两次。
8、dos equis
如下:
int i = 0;
char x = ‘X’;
System.out.println(true?x:0);
System.out.println(false?i:x);
打印什么?X88
需要注意到的是i和x的类型不一样,平常使用的都是相同类型的数据,所以不会出现这些似非而是的东西。
看三条规则:
(a)如果两个操作数的类型相同,表达式的类型是确定的,
(b)如果一个操作数的类型是T,T可以是short,char,byte,而另一个操作数是int常量,那么最终的类型是T
(c)如果两个操作数的类型不一样,需要进行类型扩展,最终的表达式类型是扩展类型。
因此上述两个输出语句,第一个类型是char,而第二个类型是int,故打印了X88
提示:在表达式语句中最好使用两个类型相同的操作数,当然了一般我们也是无意中这样做的。
9、半斤
给出变量的声明,使x+=i合法,而使x=x+i不合法;
这是考察复合赋值符和简单赋值的区别。
java语言规范说明复合赋值E1 op= E2等价于简单赋值E1=(T)(E1 op E2),其中T是E1的类型。
看过之后,就会发现其实复合赋值符不仅简单的进行运算,而且还会自动进行类型转换。
因此声明为short x = 0;int i=123456;可以使得x+=i合法,而使x=x+i不合法
提示:请不要将复合赋值操作符作用于byte,short,char类型变量。
10、八两
与谜题9相反,给出声明。使得x = x + i合法,而使得x+=i不合法
复合赋值操作符:要求两个操作数都是基本的数据类型;
简单赋值符:允许左侧为对象引用,所以可以使用它们来表示任何想要表示的内容,只要表达式的右侧与左侧的变量是赋值兼容的即可
Object x= “sdjhg”;
String i= “sadgag”;
这样的声明可以使x=x+i合法,而使x+=i不合法。
综观本章,都是着眼于一些细小而神奇的地方,有些地方其实,我们已经在避免,几乎不会使用那样的表达,比如条件表达式,半斤八两这样的赋值。