java表达式陷阱

1.赋值运算

1.1 表达式直接赋值
int a = 1;
a = 2;
System.out.println(a);
1.2 同一表达式多个赋值
int a = 10;
int b = a+(a=5)+a+(a=10);
System.out.println(b);
System.out.println(a);

运算过程如下:
int b = a+(a=5)+a+(a=10);
(1)		10+(a=5)+a+(a=10)				a = 5
(2)		10+5+a+(a=10)					a = 5
(3)		10+5+5+(a=10)					a = 10
(4)		10+5+5+10
最终结果:a=10,b=30
1.3 多个括号的赋值
int i = 1;
i = (i=i+(i+(i=2)+i)+i)+3;
System.out.println(i);

计算过程如下:
    i = (i=i+(i+(i=2)+i)+i)+3				i=1
(1) i = (i=1+(1+(i=2)+i)+i)+3				i=2
(2) i = (i=1+(1+ 2 +  2)+2)+3				i=2
(3) i = (i=      8        )+3				i=8
(3) i = 11                   				i=11
最终结果:11

2.自增操作

2.1 自增(++)与加(+)组合
int i = 1;
System.out.println(i+++i+++i+++i++);

思考过程如下:
(1) 拆解:可以从最右边进行拆解,一步步来进行:
(2)i++ + i++ + i++ + i++			i = 1
(3)1   + i++ + i++ + i++			i = 2
(4)1   + 2   + i++ + i++			i = 3
(5)    3     + i++ + i++			i = 3
(6)    3     + 3   + i++			i = 4
(7)            6   + i++			i = 4
(8)            6   + 4				i = 5
最终结果:10

3.关系运算:==

3.1 不同基本数据类型间的比较
int a = 10;
int b = 10;
doublc c = 10.0;

//两个值相等,结果为true
System.out.println(a==b);
//先将a的值由int->double,然后再比较a与c的值
System.out.println(a==c);
3.2 数学运算导致小数精度不准
System.out.println(3.14 * 10 == 31.4);
结果:false

计算机中各小数逼近值如下:

  • 0.5 = 1/2
  • 0.25 = 1/4
  • 0.125 = 1/8
  • 0.0625 = 1/16
  • 0.03125 = 1/32
  • 0.015625 = 1/64
  • 0.0078125 = 1/128

计算机表示小数时,有些小数并不能精确表示,只能通过无限逼近的形式表示:

3.14=3+0.125+0.0078125+...

3.14是一个不能精确表示的数,因此会有精度问题,jvm计算的值为:

3.14 × 10 = 31.400000000000002

3.3 Integer自动装箱/拆箱问题

Integer a = 1;
Integer b = 1;
System.out.println(a == b);
结果:true

a = 127;
b = 127;
System.out.println(a == b);
结果:true

a = 128;
b = 128;
System.out.println(a == b);
结果:false

java自动装箱功能

  1. 首先判断当前值的范围是不是在byte的表示范围内 -128 ~ +127;
  2. 如果在此范围内,JVM会在内存中创建一个数组,该数组中有256个数据数据是从-128 +127,自动装箱的对象 保存在一个静态数组中;
  3. 如果不在此范围内,每次均new Integer().

4.逻辑运算符&/&& |/||

System.out.println(true | false & false);
结果: true

结论:java语言中,与&运算比或|运算级别高

5.移位运算:<</>>/>>>

int a = 10;
System.out.println(a<<1);
System.out.println(a<<2);
System.out.println(a<<32);
System.out.println(a<<33);

结果:
20
40
10
20

左移操作时,byte类型会隐式转换成int:

byte b = 1;
System.out.println(b<<1);
System.out.println(b<<2);
System.out.println(b<<8);
System.out.println(b<<9);

结果:
2
4
256
512

结论:

  1. 左移(<<)几位,相当于将数字扩大2的n次方倍,如左移1位,相当于扩大2倍速(2的1次方为2),左移2位,相当于扩大4倍(2的2次方为4);
  2. 左移32位,会变成原来的数据大小(相当于左移0位),左移33位,相当于左移1位;这里的32,是指数据类型的位数,如果移动的是long类型数据,需要左移64位才变成原来的数。
  3. 移位运算,操作数必定是int或long类型,如果是byte或short,也会隐式转换成int.

6.三目运算符

6.1 三目运算时,如果条件表达式确认了取哪一个值,那么另一个值将不再进行运算
int a = 2;
int b = 1;
int c = a > b ? (a = 4) : (b = 3);
System.out.println(a);
System.out.println(b);
System.out.println(c);

结果:
4
1
4
6.2 三目运算是一个表达式,作为一个表达式,应该有一个结果,这个结果应该有一种唯一确定的数据类型

示例一:

int a = 10;
double d = 9.5;
System.out.println( a > d ? a : d );

结果:
10.0

说明:数据类型不同时,会先统一数据类型,再进行计算。这里会先将int转换成double,再计算表达式的值,即:

double x = a > d ? a : d

示例二:

System.out.println( 3 > 2 ? 1 : true );

结果:1

说明:

  1. 3 > 2 ? 1 : true 该表达式虽然数据类型不同,但能通过编译;

  2. java中,基本数据类型有一个自动装箱的过程,以上表达式等价于:

    	Object x = 3 > 2 ? new Integer(1) : new Boolean(true);
    

7.复合赋值表达式:+=/-=/×=...

示例一:复合表达式与处增结合
int a = 1;
a+=a++;
System.out.println(a);

结果:
2

计算过程如下:
1)a = a + a++;	a=1
2)a = 1 + a++;  a=2
3)a = 1 + 1
4)a = 2
示例二:多个复合表达式结合
int a = 1;
a+= a+= a++;
System.out.println(a);

结果:
3

计算过程如下:
1)a+=   (a+= a++);       //找到第一个+=,将后面的内容添加一个括号
2)a=a + (a+= a++);       //计算第一个+=:拆成"a=a+xx"的形式
3)a=1 + (a+= a++);       //此时a=1
4)a=1 + (a= a + a++);    //计算括号中+=:拆成“a=a+xx"的形式
5)a=1 + (a= 1 + a++);    //将a=1代入
6)a=1 + (a= 1 + 1);      //将a=1代入,此时a=2
7)a=1+  (a= 2);          //赋值,a=2
8)a=1+2;
9)a = 3
示例3:复合、自增、赋值结合求值
int a = 1;
a+=(a=2)+ (a+=(a=3)+a++);
System.out.println(a);

结果:
8

计算过程如下:
a+=((a=2)+ (a+=(a=3)+a++));      //找到第一个+=,将后面的表达式添加一个括号
a=a+((a=2)+ (a+=(a=3)+a++));     //将+=拆成"a=a+xx"
a=1+((a=2)+ (a+=(a=3)+a++));     //将a=1代入
a=1+(2+ (a+=(a=3)+a++));         //计算a=2,此时a=2
a=1+(2+ (a+=((a=3)+a++)));       //找到第二个+=,将后面的表达式添加一个括号
a=1+(2+ (a=a+((a=3)+a++)));      //将+=拆成"a=a+xxx"
a=1+(2+ (a=2+((a=3)+a++)));      //代入a的值,此时a=2
a=1+(2+ (a=2+(3+a++)));          //计算a=3,此时a=3
a=1+(2+ (a=2+(3+3)));            //计算a++,此时a=4
a=1+(2+ (a=8));
a=1+(2+ 8);
a = 11
示例4:复制表达式与自动类型转换

在java中,类型转换时,可以如下操作:

int a = 1;
//1.低类型向高类型转换,可以自动转换
double b = a;
//2.高类型向低类型转换,需要强制类型转换
byte c = (byte)a;

但复合表达式中,自动类型转换并不是这样:

int a = 1;
a+=3.5;
System.out.println(a);

结果:
4

在这里+=符号右边的操作数被转化成左边的类型,不管右边是否高于左边,全部自动转换成左边的形式。

即上面的计算等价于:a = a + (int)3.5

示例5

int a = 1;
a+= 4294967295L;
System.out.println(a);

结果:
0

计算过程:
a=0000-0000 0000-0000 0000-0000 0000-0001
b=0000-0000 0000-0000 0000-0000 0000-0000 1111-1111 1111-1111 1111-1111 1111-1111

计算时,表达式如下:
a = a + (int)4294967295L
因此,实际上进行计算的是
a=0000-0000 0000-0000 0000-0000 0000-0001
b=1111-1111 1111-1111 1111-1111 1111-1111
由于结果超过了int的范围,超过32位的部分会截断,最终结果为0.

转载于:https://my.oschina.net/funcy/blog/2999977

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值