1、操作符注意事项
- 操作运算符号
- 几乎所有的操作服
只能运用于基本类型,==、=!、=除外,包装类型若果运用操作服进行计算时,会进行自动拆箱和装箱操作。
Integer i = 10;
Integer j = 11;
System.out.println(i+j);
- jvm指令解析
//jvm指令解析
0 iconst_3 //将变量3推送至栈顶
1 invokestatic #1 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;> //调用Integer.valueOf方法,把栈顶元素转换成包装类型,并压入栈顶
4 astore_1 //将栈顶元素赋值给变量1
5 iconst_4
6 invokestatic #1 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
9 astore_2
10 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
13 aload_1 //将本地变量1压入栈顶
14 invokevirtual #3 <java/lang/Integer.intValue : ()I> //转换为int类型
17 aload_2 //将本地变量2压入栈顶
18 invokevirtual #3 <java/lang/Integer.intValue : ()I> //转换为int类型
21 iadd //栈顶两个元素相加
22 invokevirtual #4 <java/io/PrintStream.println : (I)V>
25 return
1、运算操作符只能运用于基本数据类型,当包装类型进行计算时会先转化为基本数据类型 2、比较运算符进行比较时,任何类型都可以
2、类型转换(类型提升、窄化)
- 包装类型在进行的时候会进行类型的转化
- char、byte、short在进行计算时会进行自动提升为int类型
byte b = 1;
short s = 10;
short s2 = (short) (b + s);
- jvm指令解析
0 iconst_1 //常量1入栈
1 istore_1 //赋值给变量1
2 bipush 10 //常量10入栈
4 istore_2 //赋值给变量2
5 iload_1 //变量1押入操作数栈
6 iload_2 //变量2押入操作数栈
7 iadd //计算相加
8 i2s //转化成short类型
9 istore_3 //赋值给变量3
10 return
由于Java 指令集的操作码总数不能超过256个,所以不能为每种类型都规定相应的指令,因此只能先转化成int类型进行计算,然后再转化成相应的制定类型。 更深层的原因char、byte、short的大小。 由于Java 栈上分配的最小单位 slot 就是 4 字节,所以char、byte、short在栈中都是占用的四个字节。但是他们会在堆中产生区别解释
- 关于精度损失问题[[2、浮点类型精度损失]]问题
3、前置++、后置++、+=
- 代码
int i = 10;
i = i++;
i = ++i;
i+=i;
i+=10;
System.out.println(i);
- 字节码分析
0 bipush 10 //常量10入栈
//i++
2 istore_1 //栈顶元素出栈赋值给变量1
3 iload_1 //变量1入栈
4 iinc 1 by 1 //变量1自增1,此时的自增1是在局部变量表中完成的。此时操作数栈中的数依然是10
7 istore_1 //栈顶元素弹出赋值给变量1
//++i
8 iinc 1 by 1 //变量一自增1.在局部变量中完成的,此时变量在局部变量中存储的是11
11 iload_1 //变量1入栈
12 istore_1 //栈顶元素出栈并赋值给变量1
//i+=i
13 iload_1 //变量1入栈
14 iload_1 //变量1入栈
15 iadd //栈顶的2个元素出栈相加,结果入栈
16 istore_1 //栈顶元素出栈赋值给变量1
//i+=10
17 iinc 1 by 10 //局部变量自增10,在局部变量表中进行
20 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
23 iload_1
24 invokevirtual #4 <java/io/PrintStream.println : (I)V>
27 return
通过字节码进行分析发现: 前置++:他是先进行自增操作,也就是在局部变量表中进行完自增操作之后,然后在压入操作数栈,之后的计算都是自增后的值。 后置++:他是后进行自增操作。他先把数值压入操作数栈,然后在变量表中进行自增操作。 例如:sout(i++);sout(i):第一个打印的是操作数栈中的值,第二句打印的时候,局部变量表中的新值已经入栈,打印的是新的值。 注意+=:当加等常量的时候,也是在局部变量表中进行的