Java解惑学习有感(一)---表达式之谜

来源:互联网 发布:淘宝会员名一般叫什么 编辑:程序博客网 时间:2024/05/16 18:57

谜题1:奇数性

如何判断一个int类型的数是奇数,可用代码:i%2 != 0, 返回true为奇数,返回false为偶数,如果在一个强调性能环境中使用,用位操作符AND(&)替代取余操作更好:( i & 1) != 0

谜题2:找零时刻

在计算2.00 -1.10时是会得到很长的一串小数点后的数字的,这个时候就得用到BigDecimal()参数为String的构造器了,计算如下new BigDecimal(“2.00”).subtract(new BigDecimal(“1.10”)

谜题3:长整除

当在操作很大的数字时,千万要提防溢出—它可是一个缄默杀手。

例如:

final long MICROS_PER_DAY = 24*60*60*1000*1000;

final long MILLIS_PER_DAY = 24*60*60*1000;

当进行这两个数的整除时,得出来的结果是5,这是因为MICROS_PER_DAY在计算时是按int类型计算的,计算完成后再提升为long类型,而在计算的时候int类型已经溢出,无法将计算后的正确值返回给long类型,解决方案将计算的第一个数变成为long类型,如下:

final long MICROS_PER_DAY = 24L *60*60*1000*1000;MILLIS_PER_DAY计算不会溢出,可以不用!

谜题4:初级问题

小写字母l和数字1在大多数打字机字体中几乎一样,为避免程序的读者对二者产生混淆,千万不要使用小写的l作为long型字面变量的结尾或是作为变量名。

谜题5:十六进制的趣事

首先要明白下面这点知识:

十六进制能表示的最大10进制数:

1个字节:最大0xFF = 255(存储类型byte和char)

2个字节:最大0xFF FF = 65535(存储类型short和int)

4个字节:最大0xFF FF FF FF = 4294967295(存储类型为int和long)

8个字节:最大0xFF FF FF FF FF FF FF FF = 18446744073709551616(存储类型为long)

java在计算:Long.toHexString(0x100000000L+0xcafebabe)

这道题并不会是去执行十六进制正常的相加,而是会把0xcafebabe看成是int类型,则第8位为最高位,是被置位的了,所以0xcafebabe表示的是一个负数,它等于十进制数值-889275714,把它提升为long类型的数值0xffffffffcafebabeL,再与0x0000000100000000L进行相加,最后结果为cafebabe,解决方案只需用一个long十六进制字面常量为表示右操作数即可,即将0xcafebabe改为0xcafebabeL

谜题6:多重转型

System.out.println((int)(char)(byte)-1);

执行过程:从int类型的-1转型为byte类型,会进行窄化基本类型转换,取后8位作为byte类型的值,此时还是-1,接着将-1转换为char类型,会进行拓宽基本类型转换,而且char类型是无符号的,所以此时转换为char的值为2的16次方-1,即65535,再进行拓宽基本类型转换为int类型,还会是65535。

记住符号扩展行为:如果最初的数值类型是有符号的,就执行符号扩展;如果它是char,那么不管它将要被转换成什么类型,都执行零扩展。

如果要将一个char数值转型为一个宽度更宽的类型,并且不希望有符号扩展,则可以直接进行转换,例如int i = c;

如果要将一个char数值转型为一个宽度更宽的类型,并且希望有符号扩展,则可以先将char转型为一个short,因为它与char具有同样的宽度,但是short是有符号的,例如int i = (short)c;

如果要将一个byt数值b转型为一个char,并且不希望有符号扩展,则可以使用位掩码来限制它,例如

char c = (char)(b & 0xff)

如果要将一个byte数值转换为char,并且希望有符号扩展,则可以直接强制转换为char,例如

char c = (char)b;

要做到明确程序要做什么!最后的结果要是什么!

谜题7:互换内容

首先要明白的一点是异或赋值操作可以实现交换变量!

且看以下代码:

int x = 1984;//(0x7c0)

int y = 2001;//(0x791)

x^=y^=x^=y;

整个执行过程是从右到左的:

int temp1 = x;

int temp2 = y;

int temp3 = x^y;

x = temp3;

y = temp2^temp3;

x = temp1 ^ y;

最后的结果是x = 0, y = 1984;

这样的执行并不能达到交换变量的内容的做法,以下代码是可以实现交换x与y的值的:

y = (x^=(y^=x))^y

总结一点是:在单个表达式中不要对相同的变量赋值两次。

谜题8:Dos Equis

char x = ‘X’;

int i = 0;

System.out.print(true ? x : 0);

System.out.print(false ? i : x);

则看到题目第一个感觉无非是这两个答案XX或者是8888,但真正的答案是X88,要想弄懂这道题,必须知道条件操作符有这么几条规则:(1)当第二、第三个操作数具有相同类型时,则就是表达式的类型;(2)当第二操作数可以用来表示第三操作数时,则第二操作数的类型是表达式的类型

(3)否则,将对操作数类型进行二进制类型的提升,而条件表达式的类型就是第二个和第三个操作数被提升后的类型。回过头来看这道题,第一条输出语句中,第二个操作数是char类型,可以用来g表示int类型的0,所以第一条输出语句输出char类型;第二条输出语句中,第二个操作数是int类型,不能用来表示char类型的’X’,所以需要将char类型进行二进制类型的提升,提升为int类型,结果输出88.

谜题9:半斤

short x = 0;

int i = 123456;

当执行x += i;时,不但不会编译错,而且可以运行成功,但输出结果为-7616

因为“+=”是复合赋值操作符会自动将所执行计算的结果转型为其左侧变量的类型。

但如果执行x = x+i;,使用简单赋值操作符就没有自动转型功能,则会编译错误,需要进行强制类型转换。

总结一下:请不要将复合赋值操作符作用于byte、short或char类型的变量。避免出现窄化失真。

谜题10:八两

继续谈谈复合赋值操作符和简单赋值操作符

复合赋值操作符要求两个操作数都是基本类型的,例如int或包装了基本类型的Integer,但是有一个例外,如果+=操作符左侧的操作数是String类型,那么它允许右侧的操作数是任意类型,在这种情况下,该操作符执行的是字符串连接操作。除了这几种,其他情况都是不被允许的。

简单赋值操作符(=)允许其左侧的是对象引用类型,只要表达式的右侧与左侧的变量是赋值兼容类型即可。

例如:

Object x = “Buy”;

String i = “Effective java”;

执行x += i;是非法的;

执行x = x+i;是合法的;

 

小结一下:

该博文为Java解惑的第一章内容的有感总结,提到了如何判断奇数,如何准确解决小数,如何避免长整除可能存在的问题,避免使用l作为变量或long基本类型变量的标识,注意十六进制的相加操作,如何使用异或赋值操作实现互换内容,三目运算符的规则,复合赋值操作符和简单赋值操作符在使用上的区别。

如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!

0 0