算数运算符
运算符 | 用途 |
---|---|
+ | 加法运算,字符串连接运算,正号 |
- | 减法运算,负号 |
* | 乘法运算 |
/ | 除法运算,当参与 / 运算的两个操作数都是整数时, 表示整数除法;否则, 表示浮点除法。 整数被 0 除将会产生一个异常, 而浮点数被 0 除将会得到无穷大或 NaN 结果。 |
% | 取模运算,两个数字相除取余数 公式:a % b = a - a / b * b 当a是小数时,公式: a % b = a - (int)a / b * b |
++、– | 自增自减运算 |
++
运算,变量自己增长1。 --
运算,变量自己减少1,用法与++
一致。
- **独立运算:**变量在独立运算时,前
++
(i++
) 和 后++
(++i
)没有区别。 - 混合运算:
- 前
++
(i++
),变量先+1,然后使用结果。【先加后用】 - 后
++
(++i
),先使用变量本来的数值,然后变量+1。【先用后加】
- 前
+符号在字符串中的操作:
- + 符号在遇到字符串的时候,表示连接、拼接的含义。
"a"+"b"
的结果是"ab"
,连接含义。
运算当中有不同类型的数据,那么结果将会是数据类型范围大的那种。
public static void main(String[] args) {
System.out.println(10 / 4); // 2 整数运算结果也是整数
System.out.println(10.0 / 4); // 2.5
double a = 10 / 4; // 先整数运算10/4得到2,再转换为double类型,得到2.0
System.out.println(a);
// 取模 %
// 公式:a % b = a - a / b * b
System.out.println(10 % 3); // 1
System.out.println(-10 % 3); // -1
// -10 - (-10) / 3 * 3
// -10 - (-3) * 3
// -10 - (-9)
// -10 + 9
// -1
System.out.println(10 % -3); // 1
// 10 - 10 / (-3) * (-3)
// 10 - (-3) * (-3)
// 10 - 9
// 1
System.out.println(-10 % -3); // -1
System.out.println(-10.5 % 3); // -1.5
// -10.5 - (int)(-10.5) / 3 * 3
// -10.5 - (-10) / 3 * 3
// -10.5 - (-3) * 3
// -10.5 - (-9)
// -10.5 + 9
// -1.5
// ++
int i = 10;
i++;
++i;
System.out.println("i = " + i);
// 作为表达式使用
// 前++: ++i 先自增,再使用
// 后++: i++ 先使用,后自增
int j = 8;
// int k = ++j; // 等价于 j = j + 1; k = j; 两条语句
int k = j++; // 等价于 k = j; j = j + 1; 两条语句
System.out.println("k = " + k + ", j = " + j);
}
练习:
int i = 1;
i = i++;
System.out.println(i);
// i 的输出结果为【1】
/*
使用临时变量:temp
1. 因为是 i++,所以先使用
2. temp = i;
3. i = i + 1;
4. i = temp;
5. 得到结果为1
*/
int i = 1;
i = ++i;
System.out.println(i);
// i 的输出结果为【2】
/*
使用临时变量:temp
1. 因为是 ++i,所以先自增
2. i = i + 1;
3. temp = i;
4. i = temp;
5. 得到结果为2
*/
赋值运算符
赋值运算符,就是将符号右边的值,赋给左边的变量。如果运算符得到一个值, 其类型与左侧操作数的类型不同, 就会发生强制类型转换。
赋值运算符 | 描述 |
---|---|
= | 等于号 |
+= | 加等于 x += 4; 等价于:x = x + 4; |
-= | 减等于 |
*= | 乘等于 |
/= | 除等于 |
%= | 取模等 |
运算顺序从右往左int num = a + b + c;
。
赋值运算符的左边只能是变量,右边可以是变量、表达式、常量值
复合赋值运算符会进行类型转换。 byte b = 2; b+=3; b++;
public class AssignOperator{
public static void main(String[] args) {
int n1 = 10;
n1 += 4;
System.out.println(n1); // 14
n1 /= 3;
System.out.println(n1); // 4
byte b = 3;
b += 2; // 等价于 b = (byte)(b + 2);
b++; // 等价于 b = (byte)(b + 1);
}
}
关系运算符
运算符 | 描述 |
---|---|
== | 比较符号两边数据是否相等,相等结果是true |
< | 比较符号左边的数据是否小于右边的数据,如果小于结果是true |
> | 比较符号左边的数据是否大于右边的数据,如果大于结果是true |
<= | 比较符号左边的数据是否小于或者等于右边的数据,如果小于结果是true |
>= | 比较符号左边的数据是否大于或者等于右边的数据,如果小于结果是true |
!= | 不等于符号 ,如果符号两边的数据不相等,结果是true |
instanceof | 判断是否为类的对象 “aaa” instanceof String 结果为true |
关系运算符,是两个数据之间进行比较的运算,运算结果都是布尔值 true
或者 false
。
关系运算符组成的表达式,我们称为关系表达式。
public class RelationalOperator{
public static void main(String[] args) {
int a = 9;
int b = 8;
System.out.println(a > b); // true
System.out.println(a >= b); // true
System.out.println(a < b); // false
System.out.println(a <= b); // false
System.out.println(a == b); // false
System.out.println(a != b); // false
boolean flag = a > b; // true
System.out.println("flag = " + flag);
}
}
因为浮点数运算是近似值,所以比较是否相等时使用“==”结果不准确。例如比较a和b是否相等,可以这样:
if (a - b < 0.00000001) {}
当运算的值小于某一定程度的时候,认为他是相等的。
逻辑运算符
运算符 | 描述 |
---|---|
&& 短路与 | 两边都是true,结果是true;一边是false,结果是false。符号左边是false,右边不再运算,效率高 |
|| 短路或 | 两边都是false,结果是false;一边是true,结果是true。符号左边是true,右边不再运算,效率高 |
& 逻辑与 | 两边都是true,结果是true;一边是false,结果是false。符号左边是false,右边继续运算,效率低 |
| 逻辑或 | 两边都是false,结果是false;一边是true,结果是true。符号左边是true,右边继续运算,效率低 |
! 取反 | ! true 结果是false;! false结果是true |
^ 异或 | 逻辑异或,当两边值不同时,结果为 true, 否则为 false |
与“&&”,或“||”,具有短路效果:如果根据左边已经可以判断得到最终结果,那么右边的代码将不再执行,从而节省一定的性能。可以有多个条件:
条件A && 条件B && 条件C
a | b | a&b | a&&b | a|b | a||b | !a | a^b |
---|---|---|---|---|---|---|---|
true | true | true | true | true | true | false | false |
true | false | false | false | true | true | false | true |
false | true | false | false | true | true | true | true |
false | false | false | false | false | false | true | false |
public class LogicOperator{
public static void main(String[] args) {
int age = 50;
if (age > 20 && age < 90) {
System.out.println("ok100");
}
if (age > 20 & age < 90) {
System.out.println("ok200");
}
int a = 4;
int b = 9;
if (a < 1 && ++b < 20) {
System.out.println("ok300");
}
System.out.println("b = " + b); // b = 9
int c = 4;
int d = 9;
if (c < 1 & ++d < 20) {
System.out.println("ok400");
}
System.out.println("d = " + d); // d = 10
int e = 4;
int f = 9;
if (e > 1 || ++f < 20) {
System.out.println("ok500");
}
System.out.println("f = " + f); // f = 9
int g = 4;
int h = 9;
if (g > 1 | ++h < 20) {
System.out.println("ok400");
}
System.out.println("h = " + h); // h = 10
System.out.println(!(60 > 20)); // false
System.out.println(!(60 < 20)); // true
boolean i = (10 > 1) ^ (3 < 5);
System.out.println("i = " + i); // false
boolean j = (10 > 1) ^ (3 > 5);
System.out.println("j = " + j); // true
}
}
练习:
boolean x = true;
boolean y = false;
short z = 46;
if ((z++ == 46) && (y = true)) {
z++;
}
if ((x = false) || (++z) == 49) {
z++;
}
System.out.println("z = " + z); // 50
三元运算符
条件表达式 ? 表达式1 : 表达式2;
三元运算符计算方式:
- 条件表达式结果是true,三元运算符整体结果为表达式1。
- 条件表达式结果是false,三元运算符整体结果为表达式2。
必须同时保证表达式A和表达式B都符合左侧数据类型的要求。三元运算符的结果必须被使用。
三元运算符可以转成if--else
语句
表达式 1 和表达式 2 要为可以赋给接收变量的类型(或可以自动转换)
public class TernaryOperator {
public static void main(String[] args) {
int a = 10;
int b = 99;
// 1. a > b 为false
// 2. 得到表达式 b--
// 3. 因为是 后--,先将b的值赋给result
// 4. result的值为99,b的值为98
int result = a > b ? a++ : b--;
System.out.println("result = " + result);
System.out.println("b = " + b);
}
}
三元运算符是一个整体,会返回范围最大的那个,比如:
System.out.println(true ? 1 : 2.0);
会输出:1.0
位运算符
处理整型类型时,可以直接对组成整型数值的各个位完成操作。这意味着可以使用掩码技术得到整数中的各个位。
运算符 | 描述 | |
---|---|---|
& (“and”) | 按位与 | 两位全为1,结果为1,否则为0 |
| (“or”) | 按位或 | 两位有一个为1,结果为1,否则为0 |
^ (“xor”) | 按位异或 | 两位一个为0,一个为1,结果为1,否则为0 |
~ (“not”) | 按位取反 | 0为1,1为0 |
public class TernaryOperatorDetail {
public static void main(String[] args) {
/* 计算 (2 & 3):
* 1. 因为计算机中都是以补码的形式计算的,所以先得到2的补码
* 2. 2为int型,4字节,所以原码为 00000000 00000000 00000000 00000010
* 3. 正数的原码和补码是一样的,所以2的补码为 00000000 00000000 00000000 00000010
* 4. 同理,3的原码和补码为 00000000 00000000 00000000 00000011
* 5. 按位运算 & (两位全为1,结果为1,否则为0)
* 00000000 00000000 00000000 00000010
* & 00000000 00000000 00000000 00000011
* ————————————————————————————————————————
* 00000000 00000000 00000000 00000010
* 6. 运算后得到的是补码,将补码转为原码(因为第一位是0,所以是正数,则三码合一)
* 7. 转换为十进制的值为 2
* */
System.out.println(2 & 3);
/* 计算 (~-2)
* 1. 先得到-2的原码 10000000 00000000 00000000 00000010
* 2. 计算-2的反码(原码符号位不变,其他位取反) 11111111 11111111 11111111 11111101
* 3. 计算-2的补码(它的反码+1) 11111111 11111111 11111111 11111110
* 4. 取反运算 ~ (0为1,1为0)
* ~ 11111111 11111111 11111111 11111110
* ————————————————————————————————————————
* 00000000 00000000 00000000 00000001
* 5. 运算后得到的是补码,将补码转为原码(因为第一位是0,所以是正数,则三码合一)
* 6. 转换为十进制的值为 1
* */
System.out.println(~-2);
/* 计算 (~2)
* 1. 先得到2的原码 00000000 00000000 00000000 00000010
* 2. 计算2的补码(三码合一) 00000000 00000000 00000000 00000010
* 3. 取反运算 ~ (0为1,1为0)
* ~ 00000000 00000000 00000000 00000010
* ————————————————————————————————————————
* 11111111 11111111 11111111 11111101
* 4. 运算后得到的是补码,将补码转为原码(因为第一位是1,所以是负数)
* 5. 首先补码转反码(负数的反码等于负数的补码-1) 11111111 11111111 11111111 11111100
* 6. 反码转原码(符号位不变,其他位取反) 10000000 00000000 00000000 00000011
* 7. 转换为十进制的值为 -3
* */
System.out.println(~2);
}
}
运算符 | 描述 | |
---|---|---|
>> | 算数右移 | 低位溢出,符号位不变,并用符号位补溢出的高位 |
<< | 算数左移 | 符号位不变,低位补0 |
>>> | 无符号右移、逻辑右移 | 低位溢出,高位补0 |
public class TernaryOperatorDetail {
public static void main(String[] args) {
/* 计算 (15 >> 2)
* 1. 先得到1的原码 00000000 00000000 00000000 00001111
* 2. 低位溢出,符号位不变,并用符号位补溢出的高位
* 3. 得到 00000000 00000000 00000000 00000011
* 4. 转换为十进制是3
* 5. 本质是 15 / 2 / 2 = 3
* */
System.out.println(1 >> 2);
/* 计算 (4 << 3)
* 1. 先得到4的原码 00000000 00000000 00000000 00000100
* 2. 符号位不变,低位补0
* 3. 得到 00000000 00000000 00000000 00100000
* 4. 转换为十进制是32
* 5. 本质是 4 * 2 * 2 * 2 = 32
* */
System.out.println(4 << 3);
}
}
这些运算符按位模式处理。例如, 如果 n 是一个整数变量,而且用二进制表示的 n 从右边数第 4 位为 1,则int fourthBitFromRight = (n & 0b1000) / 0b1000;
会返回 1,否则返回 0。利用 & 并结合使用适当的 2 的幂,可以把其他位掩掉, 而只保留其中的某一位。
& 和丨运算符应用在布尔值上时也会得到一个布尔值。这些运算符与 && 和 || 运算符很类似,不过 & 和丨运算符不采用“ 短路” 方式来求值, 也就是说,得到计算结果之前两个操作数都需要计算。
>>和<<运算符将位模式左移或右移。需要建立位模式来完成位掩码时, 这两个运算符会很方便:int fourthBitFromRight = (n & (1<< 3)) >> 3;
最后,>>>运算符会用 0 填充高位,这与>>不同,它会用符号位填充高位。不存在<<<运算符。
括号与运算符级别
从上到下优先级从高到低
运算符 | 结合性 |
---|---|
[ ] . ( ) (方法调用) | 从左向右 |
! ~ ++ – + (一元运算符) - (一元运算符) ( ) (强制类型转换) new | 从右向左 |
* / % | 从左向右 |
+ - | 从左向右 |
<< >> >>> | 从左向右 |
< <= > >= instanceof | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
| | 从左向右 |
&& | 从左向右 |
|| | 从左向右 |
? : | 从左向右 |
= += -= *= /= %= &= |= ^= <<= >>= >>>= | 从右向左 |