1、算术运算符
自增运算符++
单独使用
++a、a++无区别,如:num++ 和 ++num 结果一样
混合使用
++a:变量先+1,再做赋值运算 【先加再赋值】
a++:先做赋值运算,再让变量+1 【先赋值后加】
举例
public static void main(String[] args) {
int num1 = 10;
int num2 = 10;
++num1;
num2++;
System.out.println("num1 = " + num1); //11
System.out.println("num2 = " + num2); //11
int num3 = 100;
int b = ++num3;
System.out.println("num3 = " + num3); //101
System.out.println("b = " + b); //101
int num4 = 100;
int c = num4++;
System.out.println("num4 = " + num4); //101
System.out.println("c = " + c); //100
}
拓展
public static void main(String[] args) {
int num3 = 100;
System.out.println(++num3); //101
System.out.println(num3); //101
int num4 = 100;
System.out.println(num4++); //100
System.out.println(num4); //101
}
num4++ 输出的结果是 100; 看下println 源码:
/**
* Prints an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>int</code> to be printed.
*/
public void println(int x) {
synchronized (this) {
print(x);
newLine();
}
}
说明:
println(int x) : x = num4++; // 其实是隐式的赋值运算;
num4++先赋值给 println(int x); 然后变量 num4再+1;
2、位运算符
& 和 && 的区别
按位与 &: 左右两边都要执行 (不论第一个表达式结果是什么,第二个表达式一定会执行)
短路且 &&:当左边表达式为false时,右边表达式不执行,结果为false
^ 异或
同值取0,异值取1。
简单理解就是不进位加法,如1+1=0,,0+0=0,1+0=1
性质
交换律
结合律(即(ab)c == a(bc))
自反性 A ^ B ^ B = A ^ 0 = A
举例
public static void main(String[] args) {
int a = 10, b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a); //5
System.out.println(b); //10
}
拓展
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number
题解:
public static int singleNumber(int[] nums) {
int result = 0;
int len = nums.length;
for (int i = 0; i < len; i++) {
result = result ^ nums[i];
}
return result;
}
说明
比如1,2,3,2,3 , 根据交换规则,则等于 (22)(33)1 ,根据同假异真就是001 ,最后会得到1 。
面试题的变形:
一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?
位移
左移(<<)规则 : 低位始终补0
右移(>>)规则: 正数符号位补0,负数符号位补1(符号位为最高位,0-正数,1-负数)
无符号右移(>>>)规则:符号位(最高位)始终补0
应用一
HashMap源码中计算hashMap容量的阈值的时候,就使用到了位移运算符
源码
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
应用二
在向下游定时发送数据时, 或者调用下游接口失败时, 设置重试时间可使用位移来计算数据再次的发送时间; 从而避免频繁调用下游程序
示例
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class External {
@Builder.Default
private State state = State.Wait;
private long startAt;
private long finishAt;
@Builder.Default
private int requestTime = 1;
private long nextSendMillis; //在每一次调用失败后, 重置下次发送时间
private String errMsg;
public long setNextMillis() {
requestTime++;
long millis = (1 << (requestTime - 1)) * 60 * 1000L;
nextSendMillis = System.currentTimeMillis() + millis;
return nextSendMillis;
}
public enum State {
Wait, Sent, Failed, Finished
}
}