Java解惑读书笔记一

Java解惑读书笔记1
1。奇偶判断,应该用i%2!=0为奇数来判断,因为当为负数的时候%2的结果可能会是-1,用i%2==1会出错。(i&1)!=0使用低位是否为1来判断是否奇偶。


2。小数精确计算。java中的float和double都是不太精确的,容易造成精度丢失,比如System.out.println(2.00-1.10);结果不是0.9而是0.8999999999999999。一次我们可以用long或者int来代替浮点数(比如0.9我们可以用200-110表示来计算,最后结果除以100.0F)。或者使用BigDecimal


3.int 相乘溢出!这个最常见了,在项目中经常出现多少天等于多少毫秒之类的,如果这样算long s =  25 * 24 * 3600 * 1000,最后s=-2134967296,怎么会溢出呢,原因是这几个都是整形,最大值是2147483647,所以25天就溢出了而24天是正常的,怎么办?把25改为25L即可,它会强制转化为long型再计算,如果我把1000改为1000L,像这样long s =  25 * 24 * 3600 * 1000L,可能会溢出吗?还是会,如果前面的数字超出整形就溢出,所以应该把左边的第一个数设置为long型。


4.字面常量,所以的字面常量都是int型,不管是10进制还是16进制,除非以L结尾表示他是long型。


5.窄数字拓展到宽数字的拓展。如果是char类型,一定是无符号拓展,因为char没有负数。其他的,如果之前是正数则无符号拓展,如果是负数则有符号拓展。记住这点即可。

6.这个和上面的相似。(byte)0x90 == 0x90 吗?不等于,因为左边的会被拓展成int,而byte这个是负数,会有符号拓展,最后结果是负数和0x90当然不相等,可以加一个掩码0xFF把前面的负数去除即可 (byte)0x90 & 0xFF == 0x90,

按位与0xFF的意思是只保留数字的低8位,高位按0处理。


7.三元表达式(:?)。讨论起表达式的值,a?b:c这样的,如果b或者c一个是int或者long字面常量,而另一个是char byte short等变量,则表达式类型为char byte short。如果没有一个是字面常量,则拓展为最宽的作为表达式类型。举例
char x = 'X';
int i = 65;
System.out.println(true ? x : 65);// X
System.out.println(false ? x : 65);// A。注意这里不是65
System.out.println(true ? i : x);// 65
System.out.println(false ? i : x);// 88。注意这里不是X


8.+=符合运算。x+=i和x=x+i是不等效的,因为会涉及到类型的转化。如果x是窄的,i是宽的,x+=i编译不报错但结果可能会溢出,而x=x+i则编译不通过。所以尽量不要在复合运算左边用byte char short类型,容易溢出。举例。
		int i=10033333;
		byte b = 12;
		//编译无措,结果会溢出
		b += i;
		//编译错误 :cannot convert from int to byte
		//b = b + i;


9.++i和i++区别,这个一般人都知道,不说了

10.Integer.MAX_VALUE+1=Integer.MIN_VALUE。因为int是有符号数,最大值为0x7FFFFFFF,+1变为0x80000000,这个是负数最小值。这样看int好像是一个循环,超过最大值便成了最小值了。

11。移位.x<<y。如果x是byte,char ,short会被拓展为int再移位,怎么拓展参照前面介绍的拓展方法,如果y超过32会取对32的模,也就是说最多只能移32位,如果x是long型,则y会对64取模。举例
System.out.println(-1 << 31);// -2147483648 向左移31%32=31位
System.out.println(-1 << 32);// -1 向左移32%32=0位
System.out.println(-1 << 33);// -2 向左移33%32=1位
System.out.println(-1 << 1);// -2 向左移1%32=1位

System.out.println(-1L << 63);// -9223372036854775808 向左移63%64=63位
System.out.println(-1L << 64);// -1 向左移64%64=0位
System.out.println(-1L << 65);// -2 向左移65%64=1位



12。double和float有正无穷大和负无穷大的定义,所以double d = 1.0/0.0;这是可以编译和运行的(int和long不行),结果d为Double.POSITIVE_INFINITY。而Double.POSITIVE_INFINITY + 1 == Double.POSITIVE_INFINITY。还有一个Double.NEGATIVE_INFINITY表示负无穷大。

13.double和float有个NaN,它不等于任何数字,包括自己,double d = 0.0/0.0,d即Double.NaN

14.自动拆箱,这个最常见了,目前1.6版本支持。
// 為了兼容以前版本,1.5不會自動拆箱
System.out.println(new Integer(0) == new Integer(0));// false
// 1.4编译非法,1.5会自动拆箱
System.out.println(new Integer(0) == 0);// true


15.为什么-0x00000000==0x00000000、-0x80000000== 0x80000000.只需要知道,最高位为符号位,0表示整数,1表示负数。内存中是补码表示所有数字的,正数的补码就是其二进制码,而负数的补码需要计算,计算方法:将其绝对值按位取反。然后+1即可。举例。-0x80000000的绝对值为0x80000000,按位取反为0x7FFFFFFF,然后加1等于0x80000000,所以-0x80000000== 0x80000000。

16.Math.abs可能会负数,System.out.println(Math.abs
(Integer.MIN_VALUE));// -2147483648。原因可以abs计算方法:return (a<0)?-a:a,可参照15,知道Integer.Min_VALUE == -Integer.MIN_VALUE.同理Long也类似.

17。不要使用基于减法的比较器。为何?可能会溢出啊,比如
int x = -2000000000;
int y = 2000000000;
显然x是小于y的,如果按照x-y>0来判断,x-y最后是正的,结果就错了。
可使用比较型,如
基于整型的比较器的实现一般使用如下的方式来比较:
public int compare(Integer i1, Integer i2) {
	return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
}


18. int i=-2147483648与int i=-(2147483648)?
前面的式子可以编译通过,后面的编译不通过,为啥,因为int型字面常量,最大值为2147483647.所以int i=-(2147483647)就可以了。


小结:前面这个18个问题都是数值表达式方面的,在平时使用的时候,只要注意别溢出即可。