运算符
算术运算符
算术运算符包括: +, -, *, /, %, ++, --
+
当左右两边都是数值型时, 则做加法运算.
当左右两边只要有一方为字符串, 则做拼接运算. 任何一个 Java 对象都可以转换为字符串.
如果 + 作用于字符, 就将字符转为整数进行计算.
程序示例:
public static void main(String[] args) {
System.out.println(100 + 86); // 186
System.out.println("100" + 86); // 10086
System.out.println(100 + 3 + "Hello"); // 103Hello
System.out.println("Hello" + 100 + 3); // Hello1003
System.out.println(3.7 + "hello"); // 3.7hello
System.out.println("abc" + true); // abctrue
System.out.println('中' + "abc" + true); // 中abctrue
System.out.println('a' + 'b'); // 195
System.out.println('a' + "b"); // ab
}
代码 System.out.println(100 + 3 + "Hello"); 中, 加法从左到右依次进行.
程序示例:
public static void main(String[] args) {
String s1 = "天龙八部";
String s2 = "笑傲江湖";
String s3 = s1 + s2;
System.out.println(s3); // 天龙八部笑傲江湖
char ch1 = '男';
char ch2 = '女';
// char ch3 = ch1 + ch2; // Type mismatch: cannot convert from int to char
System.out.println(ch1 + ch2); // 52906
double num1 = 123.56;
double num2 = 100.11;
double num3 = num1 + num2;
System.out.println(num3); // 223.67000000000002
}
/
除法分为整数除法和浮点数除法. 当两个操作数都是整数时, 执行整数除法, 否则执行浮点数除法.
两个整数相除, 即便除不尽, 小数部分也会直接丢弃而不是四舍五入. 浮点数参与除法运算, 即便数学上能除得尽, 结果也是浮点数.
程序示例:
public static void main(String[] args) {
// 两个整数相除, 即便除不尽, 小数部分也会直接丢弃而不是四舍五入
System.out.println(10 / 4); // 2
double num1 = 10 / 4;
int num2 = 10 / 4;
System.out.println(num1); // 2.0
System.out.println(num2); // 2
// 浮点数参与除法运算, 即便数学上能除得尽, 结果也是浮点数
System.out.println(8.0 / 4); // 2.0
double num3 = 8.0;
int num4 = 4;
double num5 = num3 / num4;
System.out.println(num5); // 2.0
// int num6 = num3 / num4; // Type mismatch: cannot convert from double to int
}
整数被 0 除将产生一个异常, 而浮点数被 0 除将会得到一个无穷大或 NaN 结果.
程序示例:
// 整数被 0 除将产生一个异常, 而浮点数被 0 除将会得到一个无穷大或 NaN 结果
public class DivideDemo {
public static void main(String[] args) {
// System.out.println(10 / 0); // Exception in thread "main" java.lang.ArithmeticException: / by zero
System.out.println(10.0 / 0); // Infinity
System.out.println(-10.0 / 0); // -Infinity
System.out.println(0.0 / 0); // NaN
System.out.println(-0.0 / 0); // NaN
System.out.println(0.0 / 0.0); // NaN
System.out.println(0 / 0.0); // NaN
}
}
%
% 的结果根据公式计算: a % b = a - a / b * b
可以简单记忆: 取模的结果的正负号和第一个运算数相同.
程序示例:
public static void main(String[] args) {
System.out.println(10 % 3); // 1
System.out.println(-10 % 3); // -1
System.out.println(10 % (-3)); // 1 , -3 可以不要括号
System.out.println(-10 % (-3)); // -1 , -3 可以不要括号
}
程序示例:
public static void main(String[] args) {
int all_days = 59;
int weeks = 59 / 7;
int days = 59 % 7;
System.out.println(all_days + " 天等于 " + weeks + " 星期 " + days + " 天."); // 59 天等于 8 星期 3 天.
}
% 可以作用于浮点数.
如果 a % b 中的 a 是浮点数, 那么 a % b = a - (int)a / b * b
程序示例:
System.out.println(-10.5 % 3); // -1.5
System.out.println(10.5 % -3); // 1.5
System.out.println(-10.4 % 3); // -1.4000000000000004, 说明结果可能是一个近似值
++
语句 ++i; 和 i++; 独立使用时, 效果和 i = i + 1 完全一致.
程序示例:
public class ArithmeticOperatorExcercise01 {
public static void main(String[] args) {
int i = 1;
i = i++; // temp = i; i = i + 1; i = temp;
System.out.println(i); // 1
int j = 1;
j = ++j; // j = j + 1; temp = j; j = temp;
System.out.println(j); // 2
}
}
很多程序员认为前缀和后缀这种行为容易让人困惑. 在 Java 中, 很少在表达式中使用 ++ 和 --.
算术运算遇到小数有可能计算结果不精确.
程序示例:
public class test {
public static void main(String[] args) {
System.out.println(1.1 + 1.01); // 2.1100000000000003
System.out.println(1.1 - 1.01); // 0.09000000000000008
System.out.println(1.1 * 1.01); // 1.1110000000000002
}
}
获取一个整数各个位置的值的公式:
程序示例:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个三位数整数: ");
int input = sc.nextInt();
int a = input % 10;
int b = input / 10 % 10;
int c = input / 100 % 10;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
运行结果:
请输入一个三位数整数: 259
9
5
2
关系运算符
| 运算符 | 运算 |
|---|---|
| == | 相等 |
| != | 不等 |
| < | 小于 |
| > | 大于 |
| <= | 小于等于 |
| >= | 大于等于 |
| instanceof | 检查是否是类的对象 |
关系运算符也叫比较运算符.
关系运算符的结果都是 boolean 型, 也就是要么是 true, 要么是 false.
关系运算符组成的表达式叫做关系表达式.
关系表达式经常用在 if 结构的条件中或循环结构的条件中.
程序示例:
public static void main(String[] args) {
int a = 9;
int b = 8;
boolean flag = a > b;
System.out.println(flag); // true
System.out.println(a < b); // false
// int c = a > b; // Type mismatch: cannot convert from boolean to int
}
逻辑运算符
| 运算符 | 运算 |
|---|---|
| & | 逻辑与 |
| && | 短路与 |
| | | 逻辑或 |
| || | 短路或 |
| ! | 非 |
| ^ | 逻辑异或 |
逻辑运算符用于连接多个条件表达式.
逻辑运算符的运算结果也是 boolean 类型.
逻辑运算符可以分为两组:
短路与 &&, 短路或 ||, 取反 !
逻辑与 &, 逻辑或 |, 逻辑异或 ^
a & b: & 叫逻辑与, 规则: 当 a 和 b 同时为 true, 则结果为 true, 否则为 false.
a && b: & 叫短路与, 规则: 当 a 和 b 同时为 true, 则结果为 true, 否则为 false.
a | b: 叫逻辑或, 规则: 当 a 和 b 只要有一个为 true, 则结果为 true, 否则为 false.
a || b: || 叫短路或, 规则: 当 a 和 b 只要有一个为true, 则结果为 true, 否则为 false.
!a: 叫取反, 或者非运算. 当 a 为 true, 则结果为 false, 当 a 为 false, 则结果为 true.
a ^ b: 叫逻辑异或, 当 a 和 b 不同时, 则结果为 true, 否则为 false.
区分逻辑与 & 和短路与 &&: 仅当第一个条件为 false 时, 这两个运算符有区别. 当第一个条件为 false 时, 整个表达式一定为 false, 此时短路与 && 将不再执行第二个表达式, 而逻辑与 & 将继续执行第二个表达式. 实际使用中一般都用短路与, 因为效率更高.
程序示例:
public static void main(String[] args) {
int a = 10;
int b = 1;
if (a < 1 && ++b < 20) { // 第一个条件为 false, 第二个条件不执行
System.out.println("OK");
} else {
System.out.println("NO");
}
System.out.println(b); // 1
if (a < 1 & ++b < 20) { // 第一个条件为 false, 第二个条件仍执行
System.out.println("OK");
} else {
System.out.println("NO");
}
System.out.println(b); // 2
}
区分逻辑或 | 和短路或 ||: 仅当第一个条件为 true 时, 两个运算符有区别. 当第一个表达式为 true 时, 整个表达式一定为 true, 此时短路或 || 将不再执行第二个表达式, 而逻辑或 | 将继续执行第二个表达式. 实际使用中较多使用短路或, 因为效率更高.
程序示例:
public static void main(String[] args) {
int a = 1;
int b = 10;
if (a < 10 || ++b < 20) { // 第一个条件为 true, 第二个条件不执行
System.out.println("OK");
} else {
System.out.println("NO");
}
System.out.println(b); // 10
if (a < 10 | ++b < 20) { // 第一个条件为 true, 第二个条件仍执行
System.out.println("OK");
} else {
System.out.println("NO");
}
System.out.println(b); // 11
}
程序示例:
public static void main(String[] args) {
System.out.println(60 > 20); // true
System.out.println(!(60 > 20)); // false
System.out.println((10 > 1) ^ (10 > 2)); // false
System.out.println((10 < 1) ^ (10 > 2)); // true
}
可以利用短路运算符来避免错误. 例如, 在下面的表达式中:
boolean b = x != 0 && 1 / x > x + y; // no division by 0
如果 x 等于 0, 那么第二部分就不会计算. 因此, 如果 x 为 0, 也就不会计算 1 / x, 就不会出现除以 0 的错误.
赋值运算符
赋值运算符分两类:
基本赋值运算符: =
复合赋值运算符: +=, -=, *=, /=, %=
自增, 自减和复合赋值运算符会进行类型转换.
程序示例:
public class AssignOperator {
public static void main(String[] args) {
byte b = 2;
// b = b + 2; // Type mismatch: cannot convert from int to byte
b += 2; // 等价于 b = (byte)(b + 2)
System.out.println(b); // 4
// b = b + 1; // Type mismatch: cannot convert from int to byte
b++; // 等价于 b = (byte)(b + 1);
System.out.println(b); // 5
}
}
在 Java 中, 赋值是一个表达式 (expression) , 也就是说, 它有一个值, 具体来讲就是所赋的那个值. 可以使用这个值完成一些操作.
程序示例:
public class AssignOperatorDemo {
public static void main(String[] args) {
int x = 1;
int y = x += 4;
System.out.println(y); // 5
}
}
这种嵌套赋值很容易混淆, 应当分别清楚地写出这些赋值:
程序示例:
public class AssignOperatorDemo {
public static void main(String[] args) {
int x = 1;
x += 4;
int y = x;
System.out.println(y); // 5
}
}
条件运算符
基本语法: 条件表达式 ? 表达式1 : 表达式2
如果条件表达式结果为 true, 则整个表达式的值为表达式 1 的值, 否则整个表达式的值为表达式 2 的值. 表达式 1 和表达式 2 只有一个会执行.
程序示例:
public static void main(String[] args) {
int a = 10;
int b = 99;
System.out.println(a > b ? a++ : b++); // 99
System.out.println(a); // 10
System.out.println(b); // 100
System.out.println(a < b ? ++a : ++b); // 11
System.out.println(a); // 11
System.out.println(b); // 100
}
表达式 1 和表达式 2 必须是可以赋给接收变量的类型或者可以进行自动类型转换的.
程序示例:
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = a > b ? a : b;
System.out.println(c); // 20
// short d = a > b ? a : b; // Type mismatch: cannot convert from int to short
short e = a > b ? (short) a : (short) b;
System.out.println(e); // 20
short f = (short) (a > b ? a : b); // 后面的三元运算符表达式要括起来, 否则强制类型转换只对 a 起作用
System.out.println(f); // 20
double g = a > b ? a : b; // 自动类型转换
System.out.println(g); // 20.0
}
三元运算符可以修改为 if - else 语句.
语句 int res = a > b ? a : b; 等价于:
if (a > b) {
int res = a;
} else {
int res = b;
}
程序示例:
// 求三个数中的最大值
public static void main(String[] args) {
int a = 10, b = 20, c = 30;
int tmp;
/*
方法 1
if (a > b) {
tmp = a;
} else {
tmp = b;
}
if (tmp < c) {
tmp = c;
}
*/
/*
方法 2, 最推荐
tmp = a > b ? a : b;
tmp = tmp > c ? tmp : c;
*/
// 方法 3
tmp = (a > b ? a : b) > c ? (a > b ? a : b) : c; // 30
System.out.println(tmp);
}
位运算符
位运算符按位运算, 也会对符号位起作用, 是对补码进行操作的.
Java 中有 7 个位运算符:
&: 按位与, 两位全为 1 时, 结果为 1, 否则结果为 0.
|: 按位或, 两位只要有一个为 1, 则结果为 1, 否则结果为 0.
^: 按位异或: 两位不同时, 即一个为 0 而另一个为 1 时, 结果为 1, 否则结果为 0.
~: 按位取反: 0 变为 1, 1 变为 0.
>>: 算术右移, 低位溢出 (溢出就是扔掉不要了) , 符号位不变, 即用原来的符号位补现在的符号位, 并用 0 补上溢出的其余数字位. 右移一次就是除以 2, 右移两次就是除两次 2.
<<: 算术左移, 符号位不变, 低位补上 0. 左移一次就是乘以 2, 左移两次就是乘以 2 再乘以 2.
>>>: 逻辑右移, 也叫无符号右移, 规则为: 低位溢出, 高位补 0, 即不论正负, 高位一律补 0. 没有 <<<.
程序示例:
public class BitOperator {
public static void main(String[] args) {
System.out.println(2 & 3); // 0010 & 0011 = 0010
System.out.println(~-2); // 1
// -2 原码: 10000000 00000000 00000000 00000010
// -2 反码: 11111111 11111111 11111111 11111101
// -2 补码: 11111111 11111111 11111111 11111110
// ~-2 补码: 00000000 00000000 00000000 00000001, 最高位为 0
// ~-2 反码, 原码与 ~-2 补码相等, 三码合一
System.out.println(~2); // -3
// 2 的原码, 反码, 补码: 00000000 00000000 00000000 00000010
// ~2 的补码: 11111111 11111111 11111111 11111101, 最高位为 1
// ~2 的反码 (~2 的补码减 1): 11111111 11111111 11111111 11111100
// ~2 的原码: 10000000 00000000 000000000 00000011, 等于十进制的 -3
}
}
如果 n 是一个整数变量, 而且 n 的二进制表示中从右边数第 4 位为 1, 则 int fourthBitFromRight = (n & 0b1000) / 0b1000; 会返回 1, 否则返回 0. 利用并结合适当的 2 的幂, 可以屏蔽其他位, 而只留下其中的某一位.
需要建立位模式来完成位掩码时, >> 和 << 运算符会很方便:
int fourthBitFromRight = (n & (1 << 3)) >> 3;
移位运算符的右操作数要完成模 32 的运算 (除非左操作数是 long 类型, 在这种情况下需要对右操作数完成模 64 运算) .
例如, 1 << 35 的值等同于 1 << 3 或 8.
在 C/C++ 中, 不能保证 >> 是完成算术移位 (扩展符号位) 还是逻辑移位 (填充 0) . 实现者可以选择其中更高效的任何一种做法. 这意味着 C/C++ 中的 >> 运算符对负数生成的结果可能会依赖于具体的实现. Java 则消除了这种不确定性.
运算符的优先级
上一行优先级高于下一行.
只有单目运算符和赋值运算符是从右往左运算的.
与 C 或 C++ 不同, Java 不使用逗号运算符. 不过, 可以在 for 语句的第 1 和第 3 部分中使用逗号分隔表达式列表, 也就是说 Java 中的逗号只作为分隔符而不是逗号运算符.

浙公网安备 33010602011771号