一、运算符

在程序设计中经常要进行各种运算,从而达到改变变量值的目的。要实现运算,就要使用运算符。运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。

按照运算符功能来分,基本的运算符有下面几类:

  • 算数运算符
  • 赋值运算符
  • 关系(比较)运算符
  • 逻辑运算符
  • 位运算符
  • 条件(三元)运算符

1.1 算数运算符

主要用来进行算数运算。按照参与运算的操作数的个数,又可以分为一元算数运算符和二元算数运算符。

1.1.1 二元算数运算符

  • + 加运算
    • 表示两个操作数相加。a + b
  • - 减运算
    • 表示两个操作数相减。a - b
  • * 乘运算
    • 表示两个操作数相乘。a * b
  • / 除运算
    • 表示两个操作数相除。a / b
  • % 取模运算
    • a % b表示 a 除以 b 的余数。

说明:

  • / 除法运算
    • 两个整数之间做除法运算时,只保留整数部分而舍弃小数部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2;
System.out.println(result1); //2

int result2 = num1 / num2 * num2;
System.out.println(result2); //10

double result3 = num1 / num2;
System.out.println(result3); //2.0

double result4 = num1 / num2 + 0.0;
System.out.println(result4); //2.0

double result5 = (num1 + 0.0) / num2;
System.out.println(result5); //2.4
  • % 取模运算
    • 在除法运算时,一般我们要的结果是商,而取模运算,要的结果是余数。
    • 在有负整数参与运算时,结果的符号与被模数相同。
1
2
3
4
5
6
int num1 = 17;
int num2 = 5;
int result1 = num1 / num2;
int result2 = num1 % num2;
System.out.println(result1); //3
System.out.println(result2); //2
1
2
3
4
5
6
7
8
9
10
11
12
int m1 = 17;
int n1 = 5;
System.out.println("m1 % n1 =" + m1 % n1);
int m2 = -17;
int n2 = 5;
System.out.println("m2 % n2 =" + m2 % n2);
int m3 = 17;
int n3 = -5;
System.out.println("m3 % n3 =" + m3 % n3);
int m4 = -17;
int n4 = -5;
System.out.println("m4 % n4 =" + m4 % n4);

1.1.2 一元算数运算符

  • + 正号
    • 表示一个正数
  • - 负号
    • 表示一个负数
  • ++ 表示自增 1
    • (前)++ 例如 ++a
    • 先自增,然后参与运算
    • (后)++ 例如 a++
    • 先参与运算,然后自增
  • -- 表示自减 1
    • (前)-- 例如 --a
    • 先自减,然后参与运算
    • (后)-- 例如 a--
    • 先参与运算,然后自减
1
2
3
4
5
6
int a1 = 10;
int b1 = ++a1;
int a2 = 10;
int b2 = a2++;
System.out.println(a1 + " " + b1);
System.out.println(a2 + " " + b2);

注意:a = a + 1a++ 或者 ++a的区别
自增、自减运算不会改变变量的数据类型。
自增、自减运算不能用于表达式,只能用于简单变量。

1
2
3
short s = 10;
s = s + 1; //这里编译不通过
s++; // s = 11

1.1.3 算数运算符使用练习

练习:说出下面代码的运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Exercise1 {

public static void main(String[] args) {
int i1 = 10;
int i2 = 20;
int i = i1++;
System.out.println("i=" + i);
System.out.println("i1=" + i1);
i = ++i1;
System.out.println("i=" + i);
System.out.println("i1=" + i1);
i = i2--;
System.out.println("i=" + i);
System.out.println("i2=" + i2);
i = --i2;
System.out.println("i=" + i);
System.out.println("i2=" + i2);
}

}
/* 结果
i=10
i1=11
i=12
i1=12
i=20
i2=19
i=18
i2=18
*/

练习:三位数的拆分,随意给出一个 100~999 的整数,打印显示它的个位数,十位数,百位数的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Exercise2 {
public static void main(String[] args) {
int num = 996;

System.out.println("百位是" + num / 100);
System.out.println("十位是" + (num / 10) % 10);
System.out.println("个位是" + num % 10);
}
}
/* 结果
百位是9
十位是9
个位是6
*/

1.2、赋值运算符

1.2.1、基本赋值运算符

赋值运算使用=作为运算符。表示将表达式的值赋给一个变量或者对象。其格式为:
变量或者对象 = 表达式;

当赋值运算符两侧数据类型不一致时,需要按类型转换规则使用自动类型转换或者强制类型转换。
支持连续赋值。如a=b=c=8;

1.2.2、扩展赋值运算符

在赋值符=前面加上其他运算符,即构成扩展赋值运算符。常用的有:

  • +=
    • a += b等效于a = a + b
  • -=
    • a -= b等效于a = a - b
  • *=
    • a *= b等效于a = a * b
  • /=
    • a /= b等效于a = a / b
  • %=
    • a %= b等效于a = a % b

扩展赋值运算符不会改变操作数的类型:

1
2
3
4
short s = 10;
s = s + 2; //编译不通过
s += 2;
System.out.println(s); //12

开发中如果希望变量实现 +1 的操作,有几种方法?
方式一:num = num + 1;
方式二:num += 1;
方式三:num++;(推荐)

1.2.3、赋值运算练习

练习一:下面的代码中,语句一与语句二有什么区别?

1
2
3
short s = 3;
s = s + 2; //语句一
s += 2; //语句二

s+=2可以等价成s = s + 2。

练习二:下面代码的输出结果是什么?

1
2
3
4
5
6
7
8
9
    int i = 1;
i *= 0.1;
System.out.println(i);
i++;
System.out.println(i);
/* 结果
0
1
*/

i为int类型,乘以0.1后会被强制转换。

练习三:下面代码的输出结果是什么?

1
2
3
4
5
6
7
8
9
    int m = 2;
int n = 3;
n *= m++;
System.out.println("m=" + m);
System.out.println("n=" + n);
/* 结果
m=3
n=6
*/

练习四:下面代码的输出结果是什么?

1
2
3
4
5
6
    int n = 10;
n += (n++) + (++n);
System.out.println(n);
/* 结果
32
*/

++n是先加后赋值;n++ 是先赋值后加。

1.3、关系(比较)运算符

关系运算符用于比较两个值之间的大小,结果返回 boolean 型的值 true 或 false

  • > 大于
  • >= 小于或等于
  • < 小于
  • <= 小于或等于
  • == 等于
  • != 不等于

注意:区分 === 的区别。

1.4、逻辑运算符

只有布尔类型的数据才能进行逻辑运算。

关系型运算与逻辑运算的区别:
关系运算的结果是逻辑型,对操作数的类型没有限制
逻辑运算的操作数和结果都是逻辑型

Java 中的逻辑运算符:

  • 逻辑与 两个操作数均为 true,结果才为 true
    • &
    • &&
  • 逻辑或 两个操作数均为 false,结果才为 false
    • |
    • ||
  • 逻辑非 对操作数取反
    • !
  • 逻辑异或 两个操作数不同,结果才为 true
    • ^

&&&的区别:

  • 相同点:二者运算的结果相同
  • 相同点:当符号左侧的运算结果为 true 时,它们都会执行符号右侧的运算
  • 不同点:当符号左侧的运算结果为 false 时,虽然已经能够确定运算的结果一定为 false,&仍然会执行符号右侧的运算,但&&不再执行
  • 实际开发中,一般使用的都是&&

参考以下的代码,体会&&&的区别:

1
2
3
4
5
int i = 1;
boolean b1 = (i == 3) & (++i > 0);
System.out.println(b1 + " " + i);
boolean b2 = (i == 3) && (++i > 0);
System.out.println(b2 + " " + i);

|||的区别:

  • 相同点:二者运算的结果相同
  • 相同点:当符号左侧的运算结果为 false 时,它们都会执行符号右侧的运算
  • 不同点:当符号左侧的结果为 true 时,虽然已经能够确定运算的结果一定为 true,\仍然会执行符号右侧的运算,但||不再执行
  • 实际开发中,一般使用的都是||

参考以下的代码,体会|||的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//代码段1
int i = 1;
boolean b1 = (i == 2) | (++i > 0);
System.out.println(b1 + " " + i);
boolean b2 = (i == 2) || (++i > 0);
System.out.println(b2 + " " + i);


//代码段2
int i = 1;
boolean b2 = (i == 2) || (++i > 0);
System.out.println(b2 + " " + i);
boolean b1 = (i == 2) | (++i > 0);
System.out.println(b1 + " " + i);

1.5、位运算符

实际开发工作中基本用不到,有兴趣的同学可以自行查找资料学习原码、反码和补码的内容后自行学习。

1.6、条件(三元)运算符

  • 该运算符的格式:条件表达式 ? 表达式1 : 表达式2
  • 说明:
    • 条件表达式的结果为 boolean 类型
    • 条件表达式的结果为 true,则执行表达式 1。条件表达式的结果为 false,则执行表达式 2
    • 表达式 1 和表达式 2 的值的类型可以不同,但要求可以相容
    • 表达式 1 和表达式 2 也可以是三元运算符。即三元运算符是可以嵌套的。
  • 凡是可以使用三元运算符的地方都可以改写为 if-else。反之,不成立。
  • 如果既可以使用三元运算符,也可以使用 if-else,那么优先选择三元运算符。原因:代码更简洁、运行效率更高。

练习:获取两个整数当中的较大值。

1
2
3
4
5
6
7
int m = 10;
int n = 100;

//将条件表达式用括号括起来可以提高代码的可读性
int max = (m > n) ? m : n;
System.out.println(max);

思考:使用条件运算符求三个整数当中的较大值。

1.7、运算符的优先级

一般而言,单目运算符优先级较高,赋值运算符优先级较低。算术运算符优先级较高,关系和逻辑运算符优先级较低。多数运算符具有左结合性,单目运算符、三目运算符、赋值运算符具有右结合性。

Java 语言中运算符的优先级共分为 14 级,其中 1 级最高,14 级最低。在同一个表达式中运算符优先级高的先执行。下图列出了所有的运算符的优先级以及结合性。

优先级

源代码就是一份文档,源代码的可读性比代码运行效率更重要。

  • 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成。
  • 不要过多地依赖运算符的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用()来控制表达式的执行顺序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//下面代码的可读性非常差,不建议这样写代码
int a = 5;
int b = 4;
int c = a++ - --b * ++a / b-- >> 2 % a--;

//执行结果和上面的代码一致,但可读性好很多
int a = 5;
int b = 4;
int c = (a++ - (--b * ++a / b--)) >> (2 % a--);

//执行的结果和上面的代码一致,可读性更好
int temp1 = (a++) - (--b) * (++a) / (b--);
int temp2 = 2 % (a--);
int c = temp1 >> temp2;