三、运算符
3.1 算术运算符
算术运算符 |
|
|
加法运算,字符串连接运算 |
|
减法运算 |
|
乘法运算 |
|
除法运算 |
|
取模运算,两个数字相除取余数 |
|
自增自减运算 |
3.1.1 基本运算
- 算数运算符练习:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo05 { public static void main(String[] args) { // 定义变量 int a = 5; int b = 3; System.out.println(a + b); //8 System.out.println(a - b); //2 System.out.println(a * b); //15 System.out.println(a / b); //1 System.out.println(a % b); //2 System.out.println("------------"); //整数相除,结果是整数,要得到小数,必须有小数参与运算(提升为double类型) System.out.println(5.0 / 3); //1.6666666666666667 System.out.println(5 / 3.0); //1.6666666666666667 } }
%取余注意事项:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo06 { public static void main(String[] args) { System.out.println(5 % 3); System.out.println(-5 % 3); System.out.println(5 % -3); System.out.println(-5 % -3); } }
Tips:取余结果符号与左边符号相同
3.1.2 ++和--
++ 运算,变量自己增长1。反之, -- 运算,变量自己减少1,用法与 ++ 一致。
- 独立运算:
- 变量在独立运算时, 前++ 和 后++ 没有区别 。
- 变量 前++ :例如 ++i 。
- 变量 后++ :例如 i++ 。
- 混合运算:
- 和其他变量放在一起, 前++ 和 后++ 就产生了不同。
- 变量 前++:变量a自己加1,将加1后的结果赋值给b,也就是说a先计算。a和b的结果都是2。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo07 { public static void main(String[] args) { int a = 1; int b = ++a; //先++,后赋值 System.out.println(a); //2 System.out.println(b); //2 } }
- 变量 后++:变量a先把自己的值1,赋值给变量b,此时变量b的值就是1,变量a自己再加1。a的结果是2,b的结果是1。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo08 { public static void main(String[] args) { int a = 1; int b = a++; //先赋值,后++ System.out.println(a); //2 System.out.println(b); //1 } }
自增自减小练习
/** * @author lscl * @version 1.0 * @intro: */ public class Demo09 { public static void main(String[] args) { int a = 10; int b = 10; int c = 10; a = b++; c = --a; b = ++a; a = c--; System.out.println(a); //? System.out.println(b); //? System.out.println(c); //? } }
答案
3.1.3 +=运算
public class Demo { public static void main(String[] args) { short s = 1; s += 1; System.out.println(s); } }
s += 1 逻辑上看作是 s = s + 1;计算结果被提升为int类型再向short类型赋值时发生错误,因为不能将取值范围大的类型赋值到取值范围小的类型,但是, s=s+1进行两次运算 , += 是一个运算符,只运算一次,并带有强制转换的特点,也就是说 s += 1
就是 s = (short)(s + 1)
,因此程序没有问题编译通过,运行结果是2;
但如果是s=s+1;那么就会出现编译报错,需要强制转换;
3.1.4 字符串注意事项
符号在遇到字符串的时候,表示连接、拼接的含义。"a"+"b"的结果是“ab”,连接含义
/** * @author lscl * @version 1.0 * @intro: */ public class Demo10 { public static void main(String[] args) { // +遇到字符串表示连接 System.out.println("df" + "bz"); //"dfbz" System.out.println("dfbz" + 10); //"dfbz10" //1. "dfbz"+5="dfbz5"; 2. "dfbz5"+5="dfbz" System.out.println("dfbz" + 5 + 5); System.out.println("dfbz" + (5 + 5)); //1. 5+5=10; 2. 10+"dfbz"="10dfbz" System.out.println(5 + 5 + "dfbz"); //1. 5+5=10; 2. 10+"dfbz"="10dfbz" System.out.println("1+1="+1+1); } }
思考?
System.out.println("1+1="+1+1);
3.1.5 常量和变量的运算
思考?下面的程序有问题吗?
/** * @author lscl * @version 1.0 * @intro: */ public class Demo { public static void main(String[] args) { byte b1 = 1; byte b2 = 2; byte b3 = 1 + 2; byte b4 = b1 + b2; } }
分析: b3 = 1 + 2
, 1 和 2 是常量,为固定不变的数据,在编译的时候(编译器javac),已经确定了 1+2 的结果并没有超过byte类型的取值范围,可以赋值给变量 b3 ,因此b3=1 + 2
是正确的。反之, b4 = b2 + b3
, b2 和 b3 是变量,变量的值是可能变化的,在编译的时候,编译器javac不确定b2+b3的结果是什么,因此会将结果以int类型进行处理,所以int类型不能赋值给byte类型,因此编译失败。
3.2 赋值运算符
赋值运算符,就是将符号右边的值,赋给左边的变量。
赋值运算符 |
|
|
赋值 |
|
加后赋值 |
|
减后赋值 |
|
减后赋值 |
|
除后赋值 |
|
取模后赋值 |
- 赋值运算符测试:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo11 { public static void main(String[] args) { // 定义变量 int i = 3; // 将3赋值给变量i i = i + 2; // 将变量i和2相加,再赋值给变量i System.out.println(i); // +=: 赋值运算符, 将=左边的变量和=右边的值进行操作,再赋值给变量 int j = 10; j += 5; // j = j + 5 System.out.println(j); int m = 10; m -= 5; // m = m ‐ 5; System.out.println(m); System.out.println("‐‐‐‐‐‐‐‐‐‐"); byte b = 1; // b = b + 2; // 错误: 不兼容的类型: 从int转换到byte可能会有损失 // b += 2; // 可以 b = (byte) (b + 2); System.out.println(b); } }
3.3 比较运算符
比较运算符又叫关系运算符,是两个数据之间进行比较的运算,运算结果都是布尔值 true 或者 false 。
比较运算符: |
|
|
比较符号两边数据是否相等,相等结果是true。 |
|
比较符号左边的数据是否小于右边的数据,如果小于结果是true。 |
|
比较符号左边的数据是否大于右边的数据,如果大于结果是true。 |
|
比较符号左边的数据是否小于或者等于右边的数据,如果小于或等于结果是true。 |
|
比较符号左边的数据是否大于或者等于右边的数据,如果小于或等于结果是true。 |
|
不等于符号 ,如果符号两边的数据不相等,结果是true。 |
/** * @author lscl * @version 1.0 * @intro: */ public class Demo12 { public static void main(String[] args) { System.out.println(3 == 3); // true System.out.println(3 == 4); // false System.out.println(3 != 4); // true System.out.println(3 > 4); // false System.out.println(3 < 4); // true System.out.println(5 <= 4); // false System.out.println(4 >= 4); // true // 注意 int i = 3; int j = 4; System.out.println(i = j); // 将j赋值给i,输出i System.out.println(i == j); // true } }
3.4 逻辑运算符
3.4.1 运算规则
- 逻辑运算符,是用来对两个布尔类型进行运算的,运算结果都是布尔值
true
或者false
运算符 |
运算规则 |
示例 |
结果 |
|
与(有假为假)并且 |
false&true |
false |
|
或(有真为真)或者 |
false|true |
true |
|
异或(相同为false,不同为true) |
false^true |
true |
|
非(取反,true为false,false为true) |
!true |
false |
|
短路与(和 |
||
一样,前面条件为false不执行后面的,效率高) |
false&&true |
false |
|
|
短路或(和 |
||
一样,前面条件为true不执行后面的,效率高) |
false||true |
true |
3.4.2 代码示例
&
:与;|
:或;!
:非;^
:异或 ;
【代码示例】
/** * @author lscl * @version 1.0 * @intro: */ public class Demo13 { public static void main(String[] args) { // & 与: 有false则false, System.out.println(false & false); // false System.out.println(false & true); // false System.out.println(true & false); // false System.out.println(true & true); // true System.out.println("‐‐‐‐‐‐‐‐‐‐‐"); // | 或: 有true则ture, System.out.println(false | false); // false System.out.println(false | true); // true System.out.println(true | false); // true System.out.println(true | true);// true System.out.println("‐‐‐‐‐‐‐‐‐‐‐"); // ! 非: 取反 System.out.println(!true); // false System.out.println(!false); // true System.out.println("‐‐‐‐‐‐‐‐‐‐‐"); // ^ 异或: 相同为false,不同为true System.out.println(false ^ false); // false System.out.println(false ^ true); // true System.out.println(true ^ false); // true System.out.println(true ^ true);// false } }
3.4.3 特殊情况
短路运算和非短路运算的结果都是一样的,唯一的区别时短路运算在前面条件符合时是不会执行后面条件的,效率较高;非短路运算则不管前面运算结果如何而一定会执行后面的运算,在特定场景下会使用到;
1)短路与运算
- 短路与:
int a = 10; int b = 10; System.out.println(a != b && a++ > 10); // false System.out.println(a); // 10
- 非短路与:
int a = 10; int b = 10; System.out.println(a != b & a++ > 10); // false System.out.println(a); // 11
2)短路或运算
- 短路或:
int a = 10; int b = 10; System.out.println(a == b || a++ > 10); // true System.out.println(a); // 10
- 非短路或:
int a = 10; int b = 10; System.out.println(a == b | a++ > 10); // true System.out.println(a); // 11
3.5 三元运算符
- 三元运算符格式:
数据类型 变量名 = 布尔类型表达式 ? 结果1 : 结果2;
三元运算符计算方式:
- 布尔类型表达式结果是true,三元运算符整体结果为结果1,赋值给变量。
- 布尔类型表达式结果是false,三元运算符整体结果为结果2,赋值给变量。
/** * @author lscl * @version 1.0 * @intro: */ public class Demo15 { public static void main(String[] args) { int a = 30; int b = 30; int c = a > b ? 100 : 20; System.out.println(c); } }
三元运算符练习
- 判断两个数是否相同
- 获取两个数的较大值
3.6 位移运算
位移运算是对于"位"直接的运算,是将任何进制的数字先转化为2进制,之后再进行移位运算;位移运算分为有符号位移和无符号位移,其中有符号位移包含左位移和右位移,无符号位移只有右位移;
3.6.1 有符号位移
1) 左移位运算
- 正数的左移位:如10 << 2,右边自动补0,左边移出位舍弃,即
00001010 --> 00101000
,结果是40。实际的意思是,每向左移动一位,就相当于乘以2
10: 00000000 00000000 00000000 00001010 10 << 2: 00000000 00000000 00000000 00101000 : 40 相当于: 10 * 2^2 = 40
- 负数的左移位:负数的左移与正数的左移一致,在右边自动补0。如-2<<2:
11111110 --->11111100
,结果为-4。
对于负数的计算记得要转成补码来运算
-2: 11111111 11111111 11111111 11111110 -2 << 2: 11111111 11111111 11111111 11111000 : -8 相当于: -2 * 2^2 = -8
Tips: 左位移N,就是乘以2^N
左位移运算代码:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo14_有符号位移_左位移运算 { public static void main(String[] args) { // 左位移N,就是乘以2^N // 10 * 2^1 System.out.println(10 << 1); // 10 * 2 = 20 // 10 * 2^2 System.out.println(10 << 2); // 10 * 4 = 40 // 10 * 2^3 System.out.println(10 << 3); // 10 * 8 = 80 System.out.println("------------------"); // -10 * 2^1 System.out.println(-10 << 1); // -10 * 2 = -20 // -10 * 2^2 System.out.println(-10 << 2); // -10 * 4 = -40 // -10 * 2^3 System.out.println(-10 << 3); // -10 * 8 = -80 } }
2) 右移位运算
- 正数的右移:如10 >> 2,左边自动补0,右边移出位舍弃,即
00001010 --> 00000010
,结果是2,实际的意思是,每向右移动一位,就相当于除以2,小数舍弃,即10/2/2=2.5,舍弃小数,结果就是2。
10: 00000000 00000000 00000000 00001010 10 >> 2: 00000000 00000000 00000000 00000010 : 2 相当于: 10 / 2^2 = 2.5 = 2 4: 00000000 00000000 00000000 00000100 4 >> 2: 00000000 00000000 00000000 00000001 : 1 相当于: 4 / 2^2 = 1
- 负数的右移:如-2 >> 2,由于二进制的首位为符号位,负数在右移过程中,为了保持负数的特性,所以左边会自动补1而不是0,即
11111110 --> 11111111
,结果为-1。
-2: 11111111 11111111 11111111 11111110 -2 >> 2: 11111111 11111111 11111111 11111111 : -1 相当于: -2 / 2^2 = -1(特殊情况) -8: 11111111 11111111 11111111 11111000 -8 >> 2: 11111111 11111111 11111111 11111110 : -2 相当于: -8 / 2^2 = -2
Tips: 有符号右位移N,就是除以2^N
有符号右位移代码:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo15_有符号位移_右位移运算 { public static void main(String[] args) { // 有符号右位移N,就是除以2^N // 10 / 2^2 System.out.println(10 >> 2); // 2 // 4 / 2^2 System.out.println(4 >> 2); // 1 System.out.println("--------------------"); // -2 / 2^1 System.out.println(-2 >> 2); // -1 // -8 / 2^2 System.out.println(-8 >> 2); // -2 } }
3.6.2 无符号位移
无符号右位移:**所谓的无符号右移,就是无论是正数还是负数,高位通通补0。**另外无符号位移没有左位移运算。
如:-2 >>> 2
,对于负数的有符号右移在左边自动补1,但是对于无符号右移,左边是自动补0。
- 1)对于正数而言,>>和>>>没区别。
2: 00000000 00000000 00000000 00000010 2 >>> 1: 00000000 00000000 00000000 00000001 : 1 相当于: 2 / 2^1 = 1 8: 00000000 00000000 00000000 00001000 8 >>> 2: 00000000 00000000 00000000 00000010 : 2 相当于: 8 / 2^2 = 2
- 2)但是对于负数而言:由于无符号右移位不管是正数还是负数,高位通通补0,这样下来就会出现这样的问题:
- -2 >>> 1:结果是2147483647(Integer.MAX_VALUE)
-2: 11111111 11111111 11111111 11111110 -2 >>> 1: 01111111 11111111 11111111 11111111(变为正数了) : 2147483647(int的最大值)
- -1 >>> 1:结果是2147483647(Integer.MAX_VALUE)
-1: 11111111 11111111 11111111 11111111 -1 >>> 1: 01111111 11111111 11111111 11111111(变为正数了) : 2147483647(int的最大值)
- -2 >>> 2:等于 Integer.MAX_VALUE / 2
-2: 11111111 11111111 11111111 11111110 -2 >>> 2: 00111111 11111111 11111111 11111110(变为正数了) : 1073741822
无符号右位移:
/** * @author lscl * @version 1.0 * @intro: */ public class Demo16_无符号位移运算 { public static void main(String[] args) { // 由于无符号右移都是在左边补0,因此对于正数而言和有符号位移是一样的,都是: 无符号右位移N,就是除以2^N // 2 / 2^1 System.out.println(2 >>> 1); // 2 / 2 = 1 // 8 / 2^2 System.out.println(8 >>> 2); // 8 / 4 = 2 System.out.println("--------------------"); // 对于负数而言,在左边补0将会把负数变为了正数,因此无符号右移会出现非常大的int数 // 11111111 11111111 11111111 11111110 ---> 01111111 11111111 11111111 11111111(变为正数了) System.out.println(-2 >>> 1); // 2147483647 // 11111111 11111111 11111111 11111111 ---> 01111111 11111111 11111111 11111111(变为正数了) System.out.println(-1 >>> 1); // 1073741823 // 11111111 11111111 11111111 11111110 ---> 00111111 11111111 11111111 11111110(变为正数了) System.out.println(-2 >>> 2); // 1073741823 } }
Tips:左移位运算只有无有符号位移,没有无符号位移运算;