算数操作符
加 | 减 | 乘 | 除 | 取余/取模 |
---|---|---|---|---|
+ | - | * | / | % |
这里稍微讲解几个注意点:
- 除法和取余的时候,被除数不能为0
- 取余可以用小数,但是没什么用~~(你都要小数你还不如直接浮点数除法得了)~~
这里关于取余的负数运算可能有人有点晕,这里稍微讲解一下
public class Test {
public static void main(String[] args) {
System.out.println(10 % 3);
System.out.println(10 % (-3));
System.out.println((-10) % 3);
System.out.println((-10)%(-3));
//输出结果为 1 1 -1 -1
}
}
取余运算,如果写成小学我们经常写的余数运算格式就是:a / b = c......d
,我们取余拿的就是d
那么d
是怎么来的呢,实际上就是d = a - (b * c)
分别解释一下这上面个运算:
- 第一个非常简单,相当于
10 / 3 = 3......1
- 第二个稍微可能有人看不懂,但是我相信写出小学写的那个算数式子没人看不懂,相当于
10 / (-3) = (-3)......1
- 第三个,看不懂就写算术式子,相当于
(-10) / 3 = (-3)......-1
- 第四个,相当于
(-10) / (-3) = 3......-1
移位操作符
上一节我们有谈到过数据的存储,我们得知整型数据在内存中存储的是补码,所以涉及到二进制位的操作符都是操作补码
左移 | 右移 |
---|---|
<< | >> |
注意:该类操作符只能操作整数
左移操作符
左移,即全部数字向左移动一位,空位补0,移到外面的直接舍去
public class Test {
public static void main(String[] args) {
int a = 3;
//原反补 00000000000000000000000000000011
int b = -3;
//原 10000000000000000000000000000011
//反 11111111111111111111111111111100
//补 11111111111111111111111111111101
System.out.println(a << 1);
//移后补码 00000000000000000000000000000110
//移后原码 00000000000000000000000000000110
//输出6
System.out.println(b << 1);
//移后补码 11111111111111111111111111111010
//移后原码 10000000000000000000000000000110
//输出-6
}
}
多试几个数就会发现,左移n位就是乘以2的n次方
右移操作符
右移操作符在Java中补的是符号位
public class Test {
public static void main(String[] args) {
int a = 8;
//原反补 00000000000000000000000000001000
int b = -3;
//原 10000000000000000000000000000011
//反 11111111111111111111111111111100
//补 11111111111111111111111111111101
int c = 9;
//原反补 00000000000000000000000000001001
System.out.println(a >> 1);
//移后原反补 00000000000000000000000000000100
//输出4
System.out.println(b >> 1);
//移后原 11111111111111111111111111111110
//移后反 10000000000000000000000000000001
//移后补 10000000000000000000000000000010
//输出-2
System.out.println(c >> 1);
//移后原反补 00000000000000000000000000000100
//输出4
}
}
就相当于整型的除以2的n次方
无符号右移操作符
补位不再补符号位,而是直接补0
public class Test {
public static void main(String[] args) {
int a = 0xffffffff;
//这里是赋予一个16进制数字
//0x带头就是指后面的是一个16进制数
System.out.printf("%x\n", a >>> 1);
//这里输出格式是以16进制打印
//打印出的结果是 0x7ffffff
}
}
这里就顺便提一下16进制和2进制的关系,2进制的4个位相当于16进制的1个位
16进制的表示是
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 a b c d e f
0xffffffff
实际上就相当于二进制的
1111 1111 1111 1111 1111 1111 1111 1111
15 15 15 15 15 15 15 15
上面的代码向无符号右移位一位,实际上就是
0111 1111 1111 1111 1111 1111 1111 1111
7 15 15 15 15 15 15 15
所以16进制就是0x7ffffff
位操作符
与 | 或 | 按位取反 | 异或 |
---|---|---|---|
& | | | ~ | ^ |
关于&
和|
,就将二进制中的0和1作为是和否去判断
0000000111 0011001100
& |
0001100011 0011000000
= =
0000000011 0011001100
~
,顾名思义就是取反,没什么可以多说的
~00000001 = 11111110
^
,二进制相同就取1,不同就取0
0011110000
^
0000110011
=
1100111100
那么根据异或的定义,我们可以得出两个重要性质
a ^ a = 0
a ^ 0 = a
//甚至可以拓展为
a ^ b ^ a= b;
//异或支持交换律,所以上面的拓展实际上就等于
a ^ a ^ b = b
用异或还可以写一个很奇怪的变量数据交换代码,可以不创建临时变量交换数值
public class Test {
public static void main(String[] args) {
int a = 3;
int b = 5;
System.out.println("交换前:a = " + a + " b = " + b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("交换后:a = " + a + " b = " + b);
}
}
举一个例子来帮助理解上面的代码,假设a = 3 b = 5
a = 3 ^ 5;
b = 3 ^ 5 ^ 5;//这个时候b = 3;
a = 3 ^ 5 ^ 3;//这个时候a = 5
当然平常不推荐这样写,只不过之前有类似不让创建临时变量而要求交换数据的题目,所以这里提及一下
增量操作符
+= | -= | *= | /= | %= |
---|---|---|---|---|
>>= | <<= | &= | |= | ^= |
举例说明一下实际意义
public class Test {
public static void main(String[] args) {
int a = 0;
a += 3;
//上面和下面效果是一样的
a = a + 3;
}
}
其他的都是类型的就不多说了
自增自减运算符
++ | – |
---|---|
自增 | 自减 |
举一个例子来帮忙解释
public class Test {
public static void main(String[] args) {
int a = 0;
a++;
System.out.println(a);
//实际上就等于a = a + 1;
}
}
但是这两个符号,写在变量名前面和后面的含义不同
public class Test {
public static void main(String[] args) {
int a = 0;
int b = 0;
System.out.println(a++);
System.out.println(a);
System.out.println(++b);
System.out.println(b);
//输出的为 0 1 1 1
}
}
自增写在前面,就是先++后使用,写在后面就是先使用后++
自减和自增是同理的,所以不再多说
关系操作符
> | >= | < | <= | != | == |
---|---|---|---|---|---|
大于 | 大于等于 | 小于 | 小于等于 | 不等于 | 等于 |
关系操作符计算的结果是boolean
类型
注意,如果限定条件比较多,比如要3 < x < 5
千万不能和上面一样直接写,只能一个一个的判断,并且结合下面的逻辑操作符把他们连起来
public class Test {
public static void main(String[] args) {
int a = 0;
//如何写 3 < a < 5,没看懂就看下面的逻辑操作符
System.out.println(a > 3 && a < 5);
}
}
逻辑操作符
&& | || | ! |
---|---|---|
逻辑与 | 逻辑或 | 逻辑非 |
就是正常的逻辑逻辑判断符,逻辑运算符只能运算boolean
类型
- 与,有假则假,全真则真
- 或,有真则真,全假则假
- 非,假真互换
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 1;
System.out.println(a == 1 && b == 1);//true
System.out.println(a == 1 && b == 0);//false
System.out.println(a == 0 || b == 0);//false
System.out.println(a == 1 || b == 0);//true
System.out.println(!(a == 0));//true
System.out.println(!(a == 1));//false
}
}
阅读完上面的代码,实际上对于逻辑运算符基本就掌握的差不多了,但是还有一些注意点值得一提
当从左向右依次判断时,&&
判断中若出现一个假直接判断为假,后方不在计算。同理,||
判断中若出现一个真直接判断为真,后方不在计算,这个被称作短路运算
public class Test {
public static void main(String[] args) {
int a = 1;
//a为0直接为假,后方不再计算, 所以本来理论上会报错的代码没有报错
System.out.println(a == 0 && 10 / 0 == 0);
int b = 1;
//b为1直接为真,后方不再计算,所以本来理论上会报错的代码没有报错
System.out.println(b == 1 || 10 / 0 == 0);
}
}
上面我们提到的位操作符& |
,实际上在它们识别到附近为boolean
类型的时候,就会变为逻辑操作符,但是它们不会进行短路运算
public class Test {
public static void main(String[] args) {
int a = 1;
System.out.println(a == 0 & 10 / 0 == 0);
int b = 1;
System.out.println(b == 1 | 10 / 0 == 0);
//都会报错
}
}
条件操作符
exp1 ? exp2 : exp3
如果exp1
为true
,则表达式的值为exp2
,否则表达式的值为exp3
public class Test {
public static void main(String[] args) {
int a = 0;
int b = 0;
b = (a > 5) ? 5 : 3;
System.out.println(b);
//输出3
}
}
操作符优先级
操作符是有优先级的,如果表达式比较复杂,那么表达式可能就不会按照我们预想的方式进行运算
但是操作符的优先级多而杂,不推荐记忆,推荐在表达式中适当的加上括号保证运算符合我们的要求即可