java运算符(算数运算符、三目运算符、位运算符)

64 阅读9分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

1 运算符:算术运算符

算术运算符的注意问题

  • 如果对负数取模,可以把模数负号忽略不记,如:5%-2=1。 但被模数是

    负数则不可忽略。此外,取模运算的结果不一定总是整数。

%:求余运算符。

求余运算的结果不一定总是整数,它的计算结果是使用第一个操作数除以第二个操作数,得到一个整除的结果后剩下的值就是余数。由于求余运算也需要进行除法运算,因此如果求余运算的两个操作数都是整数类型,则求余运算的第二个运算数不能是0,否则将引发除以零异常。如果求余运算的两个操作数中有1个或者2个都是浮点数,则允许第二个操作数是0或0.0,只是求余运算的结果是非数:NaN。0或0.0对零以外的任何数求余都将得到0或0.0。

当计算两边都是正数,如果左边小于右边,那么结果就是左边;如果左边等于右边,那么结果就是为0。
System.out.println(-10%-3);//-1
System.out.println(-2%5);//-2
System.out.println(2%-5);//2
System.out.println(-2%-5);//-2
如果运算时出现负数,先忽略负号,计算出结果之后,左边的数是正数,那么结果就为正,反之为负。
应用:开关算法:任何数模以2结果01

/:除法运算符。

除法运算符有些特殊,如果除法运算符的两个操作数都是整数类型,则计算结果也是整数,就是将自然除法的结果截断取整,例如19/4的结果是4,而不是5。如果除法运算符的两个运算数都是整数类型,则除数不可以是0,否则将引发除以零异常。但如果除法运算符的两个操作数有1个是浮点数,或者2个都是浮点数,则计算结果也是浮点数,这个结果就是自然除法的结果。而且此时允许除数是0,或者0.0,得到结果是正无穷大或负无穷大。

  • 对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只 保留整数部分而舍弃小数部分。 例如:int x=3510;x=x/1000*1000; x的 结果是?

  • “+”除字符串相加功能外,还能把非字符串转换成字符串.例如: System.out.println(“5+5=”+5+5); //打印结果是? 5+5=55 ?

思考1: short s = 3; s = s+2; ① s += 2; ② ①和②有什么区别?

从结果中个看出,当指令为s=s+2进行编译时,会报错. 原因是数字2是int型的常量,s+2会自动转换成int型,将一个int型赋给一个short型的s,自然编译会出错。 如果一定要使用s+2的话,可以将s+2改为(short)(s+2),这时(short)将(s+2)的值强转为short型,这时便可以将(s+2)的值赋给s. 为什么s+=2不会报错呢? 因为编译器自动将+=运算符后面的操作数强制转换为前面变量的类型,所以s+=2不会报错. 同时类似的还有: -= *= /= %=

++自增运算符

i++和++i

int i = 0; i = i++; System.out.println(i) //结果为 0

原因: i++:先取值后运算(先取局部变量 i 的值放入操作数栈计算,后将局部变量的 i 自增) ++i : 先运算后取值(先将局部变量的 i 自增,再将 i 放入操作数栈计算)

package pers.mobian.questions01;
 
 
public class test01 {
    public static void main(String[] args) {
        int i = 1;
        i = i++;
        int j = i++;
        int k = i + ++i * i++;
        System.out.println("i="+i);
        System.out.println("j="+j);
        System.out.println("k="+k);
    }
}

结果:i = 4;j = 1; k = 11 底层原理

三目运算符 (条件表达式)?表达式1:表达式2;

  • 代码案例1
public static void main(String[] args) {
    int a = 1;
    int b = 1;

    // int类型(9)转换为double类型(9.0D)
    System.out.println(a == b ? 9.9 : 9);
    // (98)在char取值范围内,转换为对应ASCII码
    System.out.println(a == b ? 'a' : 98);
    // 超出char取值范围,统一转为int类型
    System.out.println(a == b ? 'a' : Integer.MAX_VALUE);
    // 触发二元数字提升,统一转为变量int类型
    System.out.println(a == b ? 'a' : b);
    System.out.println(a != b ? 'a' : b);
}

// 输出结果
9.9
a
97
97
1

Java基础进阶系列-08之结合JLS深度解读三目运算符

练习题

  • 考查运算符的优先级
class Demo{
	public static void main(String[] args){
	int x=0,y=1;
	if(++x==y-- & x++==1||--y==0)
	System.out.println("x="+x+",y="+y);   //x = 2,y = 0;
	else
		        System.out.println("y="+y+",x="+x);
	}
}
  • 编写代码实现两个变量值交换,int m = 3, n =5;
答案一:
int temp = m;
m = n;
n = temp;
答案二:
m = m + n;
n = m - n;
m = m - n;
答案三:
m = m ^ n;
n = m ^ n;
m = m ^ n;
  • 如何求一个0~255范围内的整数的十六进制值,例如60的十六进制表示形式3C

位运算符

  • &:按位与。
  • |:按位或。
  • ~:按位非。
  • ^:按位异或。
  • <<:左移运算符。
  • >>: 右移运算符
  • >>>:无符号右移运算符
  • 在这里插入图片描述 按位非只需要一个操作数,这个运算符将把操作数在计算机底层的二进制码按位取反。如下代码测试了按位与和按位或运算的运行结果。
        //将输出1
        System.out.println(5 & 9);
        //将输出13
        System.out.println(5 | 9);

在这里插入图片描述 左移运算符是将运算数的二进制码整体左移指定位数,左移后右边空出来的位以0填充。例如如下代码

        //输出20
        System.out.println(5 << 2);
        //输出-20
        System.out.println(-5 << 2);

在这里插入图片描述 上面的32位数是-5的补码,左移两位后得到一个二进制补码,这个二进制补码的最高位是1,表明是一个负数,换算成十进制数就是-20。

Java的右移运算符有两个:>>和>>>,对于>>运算符而言,把第一个操作数的二进制码右移指定位数后,左边空出来的位以原来的符号位填充,即如果第一个操作数原来是正数,则左边补0;如果第一个操作数是负数,则左边补1。>>>是无符号右移运算符,它把第一个操作数的二进制码右移指定位数后,左边空出来的位总是以0填充。

2 程序流程控制

2.1 if-else结构

分支结构:if-else使用说明  条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量  语句块只有一条执行语句时,一对{}可以省略,但建议保留  if-else语句结构,根据需要可以嵌套使用  当if-else结构是“多选一”时,最后的else是可选的,根据需要可以省略  当多个条件是“互斥”关系时,条件判断语句及执行语句间顺序无所谓 当多个条件是“包含”关系时,“小上大下 / 子上父下”

练习题

  • 实现对三个整数进行排序,输出时按照从小到大的顺序输出。
if(num1 >= num2){                     //num1 >= num2的所有情况
		if(num2 >= num3){
			System.out.println(num3 + "," + num2 + "," + num1);
		}else if(num3 >= num1){
			System.out.println(num2 + "," + num1 + "," + num3);
		}else{
			System.out.println(num2 + "," + num3 + "," + num1);
		}
	}else{                                 //num1 >= num2的所有情况
		if(num2 <= num3){
			System.out.println(num1 + "," + num2 + "," + num3);
		}else if(num3 <= num1){
			System.out.println(num3 + "," + num1 + "," + num2);
		}else{
			System.out.println(num1 + "," + num3 + "," + num2);
		}
	}

2.2 switch-case结构

switch语句有关规则

 switch(表达式)中表达式的值必须是下述几种类型之一:byte,short, char,int,枚举 (jdk 5.0),String (jdk 7.0);  case子句中的值必须是常量,不能是变量名或不确定的表达式值;  同一个switch语句,所有case子句中的常量值互不相同;  break语句用来在执行完一个case分支后使程序跳出switch语句块;如 果没有break,程序会顺序执行到switch结尾  default子句是可任选的。同时,位置也是灵活的。当没有匹配的case时, 执行default

switch和if语句的对比 if和switch语句很像,具体什么场景下,应用哪个语句呢?  如果判断的具体数值不多,而且符合byte、short 、char、int、String、枚举等几种类型。虽然两个语句都可以使用,建议使用swtich语句。因为效率稍高。  其他情况:对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广。 也就是说,使用switch-case的,都可以改写为if-else。反之不成立。

2.3 循环结构之for循环

- 语法格式

for (①初始化部分; ②循环条件部分; ④迭代部分){ ③循环体部分; }

- 执行过程:

①-②-③-④-②-③-④-②-③-④-.....-②

- 说明:

②循环条件部分为boolean类型表达式,当值为false时,退出循环 ①初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔 ④可以有多个变量更新,用逗号分隔

2.4 循环结构之while循环

语法格式 ①初始化部分 while(②循环条件部分){ ③循环体部分; ④迭代部分; } 执行过程: ①-②-③-④-②-③-④-②-③-④-...-② 说明: 注意不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环。 for循环和while循环可以相互转换

2.5 循环结构之do-while循环

语法格式 ①初始化部分; do{ ③循环体部分 ④迭代部分 }while(②循环条件部分); 执行过程: ①-③-④-②-③-④-②-③-④-...② 说明: do-while循环至少执行一次循环体。

特殊关键字的使用:break、continue

break 语句 break语句用于终止某个语句块的执行 { …… break; …… } break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是 哪一层语句块 label1: { …… label2: { …… label3: { …… break label2; …… } } }

特殊流程控制语句2continue 语句 continue只能使用在循环结构中 continue语句用于跳过其所在循环语句块的一次执行,继续下一次循环 continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环

附加:特殊流程控制语句3return:并非专门用于结束循环的,它的功能是结束一个方法。 当一个方法执行到一个return语句时,这个方法将被结束。  与breakcontinue不同的是,return直接结束整个方法,不管 这个return处于多少层循环之内

特殊流程控制语句说明break只能用于switch语句循环语句中。 continue 只能用于循环语句中。 二者功能类似,但continue是终止本次循环,break是终止本层循环。 breakcontinue之后不能有其他的语句,因为程序永远不会执行其后的语句。 标号语句必须紧接在循环的头部。标号语句不能用在非循环语句的前面。 很多语言都有goto语句,goto语句可以随意将控制转移到程序中的任意一条 语句上,然后执行它。但使程序容易出错。Java中的breakcontinue是不同 于goto的。