Java运算与控制
运算符
运算符是一种特殊的符号,用来表示数据的运算,赋值或者比较等
算术运算符
| 操作符 | 描述 | 例子 |
|---|---|---|
| + | 加法 - 相加运算符两侧的值 | A + B 等于 30 |
| - | 减法 - 左操作数减去右操作数 | A – B 等于 -10 |
| * | 乘法 - 相乘操作符两侧的值 | A * B等于200 |
| / | 除法 - 左操作数除以右操作数 | B / A等于2 |
| % | 取余 - 左操作数除以右操作数的余数 | B%A等于0 |
| ++ | 自增: 操作数的值增加1 | B++ 或 ++B 等于 21(区别详见下文) |
| -- | 自减: 操作数的值减少1 | B-- 或 --B 等于 19(区别详见下文) |
| + | 字符串连接 | “lns”+"love"+"zlr" = "lnslovezlr" |
代码讲解
// / 整除使用
// 注意:整数被0除将会产生一个异常,浮点书被0除将会得到Infinity结果
10 / 4; // 2
10.0 / 4 // 2.5
double d = 10 / 4; // 2.0 int -> double
double i = 10.0/0; // Infinity 无穷的意思
// % 使用
// 取模的本质 公式: a % b = a - a / b * b (当 a 是整数) a % b = a - (int)a / b * b (当 a 是浮点数,但是是近似值)
10 % 3 // 1
-10 % 3 // -1
10 % -3 // 1
-10 % -3 // -1
// 总结得出取模的正负取决于被模数
关系运算符
关系运算符的结果都为boolean类型, true / false
关系运算符组成的表达式我们称为关系表达式
| 运算符 | 描述 | 例子 |
|---|---|---|
| == | 检查如果两个操作数的值是否相等,如果相等则条件为真。 | (A == B)为假 |
| != | 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 | (A != B) 为真 |
| 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 | (A> B)为假 | |
| < | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 | (A <B)为真 |
| >= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 | (A> = B)为假 |
| <= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 | (A <= B)为真 |
| instanceof | 用于判断对象的运行类型是否为某某类型或者是某某类型的子类 | “XX” instanceof String 为真 |
逻辑运算符
用于连接多个条件(多个关系表达式)
| 操作符 | 描述 |
|---|---|
| && 短路与 | 如果某一个条件为false,则后面的条件不用判断,结果为false |
| & 逻辑与 | 全部条件都要执行 |
| II 短路或 | 如果某一个条件为true,则后面的条件不用判断,结果为true |
| I 短路或 | 全部条件都要执行 |
| !取反 | 取反:true -> false ; false -> true |
| ^异或 | 如果两个条件都为true或者false则返回false,反之返回true |
举例
习题练习
// 习题1
int x = 5,y = 5;
if(x++ == 6 & ++y == 6) x = 11; // 逻辑与 & ; 结果 x = 6, y = 6
// 习题2
int x = 5,y = 5;
if(x++ == 6 && ++y == 6) x = 11; // 短路与 && ; 结果 x = 6, y = 5
// 习题3
int x = 5,y = 5;
if(x++ == 5 | ++y == 5) x = 11; // 逻辑或 | ; 结果 x = 11, y = 6
// 习题4
int x = 5,y = 5;
if(x++ == 5 || ++y == 5) x = 11; // 短路或 || ; 结果 x = 11, y = 5
// 习题5
boolean x = true, y = true;
short z = 46;
if((z++ == 46) && (y = true)) z++;
if((x = false) || (++z == 49)) z++;
// 结果:z = 50
赋值运算符
将某个运算后的值赋给指定的变量
| 操作符 | 描述 | 例子 | |||
|---|---|---|---|---|---|
| = | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C | |||
| + = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = C + A | |||
| - = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = C - A | |||
| * = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = C * A | |||
| / = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A,C 与 A 同类型时等价于 C = C / A | |||
| (%)= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = C%A | |||
| << = | 左移位赋值运算符 | C << = 2等价于C = C << 2 | |||
| >> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 | |||
| &= | 按位与赋值运算符 | C&= 2等价于C = C&2 | |||
| ^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 | |||
| = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
注意细节
- 运算顺序从右往左
- 复合赋值运算符会进行类型转换(上文强制类型转换中有详细介绍)
条件运算符
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
// 如果条件的表达式为 true ,运算后的结果表达式1,反之运行表达式2
// 格式:条件表达式 ?表达式1 : 表达式2
// 可以理解为如下
if(true)
return 表达式1
else
return 表达式2
位运算
进制转换
其他进制转换成十进制
规则:从最低位(右边)开始,将每个位上的数提取出来,乘以进制(其他进制的进制数)的(位数-1)次方,然后求和
// 举例:八进制转换成十进制
0234 = 4*8^0 + 3*8^1 + 2*8^2 = 156
十进制转换成其他进制
规则:将该数不断除以进制(其他进制的进制数),直到商为0为止,然后将每步得到的余数倒过来,就是对应的进制数
举例: 十进制转换成二进制
// 将34转换成二进制 0B0010_0010
34 / 2 = 17 34 % 2 = 0
17 / 2 = 8 17 % 2 = 1
8 / 2 = 4 8 % 2 = 0
4 / 2 = 2 4 % 2 = 0
2 / 2 = 1 2 % 2 = 0
1 / 2 = 0 1 % 2 = 1
// 结果反转 10_0010 高位补齐 -> 0010_0010
位运算符
| 操作符 | 描述 | 例子 |
|---|---|---|
| & | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
| 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 | |
| 〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
| << | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
| >> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
| >>> | 无符号右移,按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
计算机底层运行实例
引入原码,反码,补码
- 二进制的最高位是符号位:0表示正数,1表示负数
- 自然数的原码,反码,补码都是相同的(0的反码,补码都是0)
- 负数的反码等于它的原码符号位不变,其他位取反
- 负数的补码等于它的反码+1(负数的反码等于它的补码-1)
- 计算机运行的数据以补码的方式进行运算,但是输入输出的都是原码
注意细节
无符号右(>>>):无论是正数还是负数,都是高位补0
负数右移(>>):高位补符号位1 ; 负数左移(<<):低位补0
正数右移(>>):高位补符号位0 ; 正数左移(<<):低位补0
// 运用补码原码知识
// 注意位运算操作的都是补码而非原码!!
System.out.println(2 & 6); // 2
/*
* 讲解计算机运行过程
* 运算用补码
* 1. 2的原码 ==> 00000000 00000000 00000000 00000010 == 2 的补码
* 2. 6的原码 ==> 00000000 00000000 00000000 00000110 == 6 的补码
* 运算结果为原码
* 3. 按位与& ==> 00000000 00000000 00000000 00000010 == 6 的原码 结果为2
*/
System.out.println(~-2); // 1
/*
* 讲解计算机运行过程
* 运算用补码
* 1. -2的原码 ==> 10000000 00000000 00000000 00000010
* 2. -2的补码 ==> 11111111 11111111 11111111 11111110
* 3. ~-2的补码 ==> 00000000 00000000 00000000 00000001
* 运算结果为原码
* 3. 原码结果为 00000000 00000000 00000000 00000001 == 1
*/
System.out.println(-2 >> 3); // -1
/*
* 讲解计算机运行过程
* 运算用补码
* 1. -2的原码 ==> 10000000 00000000 00000000 00000010
* 2. -2的补码 ==> 11111111 11111111 11111111 11111110
* 3. -2>>3的补码 ==> 11111111 11111111 11111111 11111111
* 4. -2>>3的反码 ==> 11111111 11111111 11111111 11111110
* 运算结果为原码
* 5. 原码结果为 10000000 00000000 00000000 00000001 == -1
*/
运算符优先级
| 类别 | 操作符 | 关联性 | ||
|---|---|---|---|---|
| 后缀 | () [] . (点操作符) | 左到右 | ||
| 一元 | expr++ expr-- | 从左到右 | ||
| 一元 | ++expr --expr + - ~ ! | 从右到左 | ||
| 乘性 | * /% | 左到右 | ||
| 加性 | + - | 左到右 | ||
| 移位 | >> >>> << | 左到右 | ||
| 关系 | > >= < <= | 左到右 | ||
| 相等 | == != | 左到右 | ||
| 按位与 | & | 左到右 | ||
| 按位异或 | 左到右 | |||
| 按位或 | 左到右 | |||
| 逻辑与 | && | 左到右 | ||
| 逻辑或 | 左到右 | |||
| 条件 | ?: | 从右到左 | ||
| 赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 | |
| 逗号 | , | 左到右 |
控制结构
控制循环类型
-
顺序控制:程序从上到下逐行地执行,中间没有跳转和任何判断
-
分支控制:if - else 判断
// 单分支 if(条件表达式){ 执行语句; } // 双分支 if(条件表达式){ 执行语句; }else{ 执行语句; } // 多分支 if(条件表达式){ 执行语句; }else if(条件表达式){ 执行语句; }else{ } -
嵌套分支:在一个分支结构中嵌套另一层分支结构(最好不要超过三层)
-
switch分支结构
switch(表达式){ // 表达式有具体的值 case 常量 1:语句一; // 表达式代表一个具体值,常量1与该值进行比较,相同则运行语句一 break; // 退出switch循环,否则直接进行语句2的运行(无需比较常量2) case 常量2:语句二; // 表达式代表一个具体值,常量2与该值进行比较,相同则运行语句二 break; .... default: 最后一个语句; // 当不等于所有值,则默认执行default语句 }细节注意:
- 表达式的数据类型必须和常量的数据类型必须相同 或者 可以自动转换的数据类型(必须是其他类型转换成int类型 比如:byte(表达式类型) - > int(常量类型))
- 表达式中具体值和常量的数据类型只能是(byte,short,int,char,enum,String)中的其中一个
- default关键字是可选择添加的
-
for循环控制 && while循环控制 && do...while循环语句
// 基本语法 for(循环变量初始化;循环条件;循环变量的变化){ 循环操作(可以多条语句); } 运行顺序: 循环变量初始化 --> [ 循环条件 --> 循环操作 --> 循环条件的变化 ] // 等价于while x 循环变量初始化; while(循环条件){ 循环操作(可以多条语句); 循环变量的变化; } // 等价于do...while 先执行后判断 循环变量初始化; do{ 循环操作(可以多条语句); 循环变量的变化; } while(循环条件);
中断控制流程语句
break语句
概念:用于退出当前循环
// 不带标签的语句
for(int i = 0;i < 10;i++){
for(int j = 0;j < 10;j++){
break; // 默认中断当下循环
}
}
// 带有标签的语句(格式: 标签名自定义 + :)
label1:
for(int i = 0;i < 10;i++){
label2:
for(int j = 0;j < 10;j++){
break label1; // 中断标签1的循环
}
}
// switch 中断语句
switch(表达式){ // 表达式有具体的值
case 常量 1:语句一; // 表达式代表一个具体值,常量1与该值进行比较,相同则运行语句一
break; // 退出switch循环,否则直接进行语句2的运行(无需比较常量2)
case 常量2:语句二; // 表达式代表一个具体值,常量2与该值进行比较,相同则运行语句二
break;
....
default: 最后一个语句; // 当不等于所有常量,则默认执行default语句
}
continue语句
概念:结束本次循环,继续进行下一次循环
// 不带标签的语句
for(int i = 0;i < 10;i++){
for(int j = 0;j < 10;j++){
continue; // 默认结束本次循环,而非退出循环,注意和break的区别
}
}
// 带有标签的语句(格式: 标签名自定义 + :)
label1:
for(int i = 0;i < 10;i++){
label2:
for(int j = 0;j < 10;j++){
continue label1; // 结束label1的本次循环,跳转到label标签匹配的循环首部
}
}
return语句
概念:表示跳出当前所在的方法,如果该方法是main主方法,则相当于结束程序
注意:break 和 continue 必须使用在 loop 或者 switch中,而return可以用在方法的任何位置