1. 基本运算符

  1. + +=
  2. - -=
  3. * *=
  4. / /=
  5. % %=
  6. -

2. 自增自减运算符

表达式是有返回值的,前置是先运算再返回,后置是先返回再运算。

  1. i++
  2. ++i
  3. i--
  4. --i

3. 比较运算符

>
<
==
>=
<=
!=

4. 逻辑运算符与短路特性

&& 与
!! 或
! 非
短路特性

5. 三元运算符

使用时要考虑代码可读性,必要时请加括号或直接用 if…else。

? : // a ? b : c

6. 位运算

首先需要明白,位运算是按内存中表示数值的位来操作数值。最后一位(从右向左)表示符号位,0 为正,1 为负,正整数没有用到的值以 0 填充。
负数同样以二进制码存储,但使用的格式是二进制补码,计算二进制补码的过程如下:

1. 求该数绝对值的二进制码
2. 对二进制码取反
3. 二进制反码加 1
(还原时则颠倒步骤,即减 1 取反)

有了这个基础知识后就可以学习位运算了。

  • ~ (NOT) 按位非(取反)
    结果就是返回数值的反码,而本质是操作数的负值减 1,例如:
求 ~-6
先计算二进制码,-6 是负数,所以以二进制补码的格式来存储:
0000 0110   求绝对值的二进制码
1111 1001   取反
1111 1010   再加 1
然后开始按位取反:
0000 0101   符号位是 0 表示正数,所以结果就是 5
求 ~5
先计算二进制码:
0000 0101
然后开始按位取反:
1111 1010
上面已经得到了按位非的运算结果,
但看起来得到的是一个负数,而负数是以二进制补码的格式来存储,
所以不能一眼看出原貌,需要进行还原:
1111 1001   对上面进行减 1
0000 0110   对上一步进行取反
所以 ~5 按位非后,得到的十进制数是 -6
  • & &= (AND) 按位与;
  • | |= (OR) 按位或;
  • ^ ^= (XOR) 按位异或,两个对应位上只有一个1时才返回1,其他情况都返回0,可以理解为不进位的加法。
    x ^ y ^ y = x
    x ^ x = 0
  • << <<= 左移(不影响正负),5<<3 表示 5*2三次方;
  • >> >>= 有符号右移(不影响正负),效果和左移相反,40>>3 表示 40/2的三次方;
  • >>> >>>= 无符号右移(总是补0);

关于如何把一堆布尔值,放在一个 32bit 的int 中存储:
设置使用按位或 |,读取使用按位与 &

7. 运算符优先级与字符串加减法操作

  • 乘除高于加减
  • 其他全部加括号
  • 字符串连接时会调用各自的toString() 方法或原生类型对应的表示
  • JDK 内部会自动把字符串拼接转换成 StringBuilder 的调用,以提高性能

8. 练习

使用位运算进行属性的读写:

package com.github.hcsp.calculation;

public class Cat {
    private static int CUTE = 0x1;
    private static int FAT = 0x2;
    private static int WHITE = 0x4;
    private int properties = 0;

    // ↑ 请勿修改以上部分的代码,请勿添加新的成员变量
    // ↓ 请补全以下代码

    /**
     * 思路:
     * 成员变量 CUTE/FAT/WHITE 应保持不变,是用来参与位运算的“砝码”
     * 设置时如果是 true,则 | 对应砝码;如果是 false,则先 & 自己,然后再 | 来修正其他两个值
     * 查询时则 & 相应砝码即可确认对应位的状态
     */

    /**
     * 使用位运算设置猫咪萌的属性
     *
     * @param cute true为萌,false为不萌
     */
    public void setCute(boolean cute) {
        // 只有 true 改为 false 或 false 改为 true 才有比较进行修改,其余两种情况当然是保持不变了(其他位同理)
        if(isCute() && !cute) {
            properties ^= Cat.CUTE; // 不影响其他位
        }
        if (!isCute() && cute) {
            properties |= Cat.CUTE; // 同样不会影响其他位
        }
        // 其他解法
        // if(cute){
        //     properties |= CUTE;
        // }else{
        //     properties &= (~CUTE);
        // }

    /**
     * 这只猫萌吗?请在此处使用位运算读取properties,得到猫是否萌的结果
     *
     * @return 萌则返回true,否则返回false
     */
    public boolean isCute() {
        return (properties & Cat.CUTE) != 0;
    }

    /**
     * 使用位运算设置猫咪胖的属性
     *
     * @param fat true为胖,false为不胖
     */
    public void setFat(boolean fat) {
        if(isFat() && !fat) {
            properties ^= Cat.FAT;
        }
        if (!isFat() && fat) {
            properties |= Cat.FAT;
        }
    }

    /**
     * 这只猫胖吗?请在此处使用位运算读取properties,得到猫是否胖的结果
     *
     * @return 胖则返回true,否则返回false
     */
    public boolean isFat() {
        return (properties & Cat.FAT) != 0;
    }

    /**
     * 使用位运算设置猫咪白的属性
     *
     * @param white true为白,false为不白
     */
    public void setWhite(boolean white) {
        if(isWhite() && !white) {
            properties ^= Cat.WHITE;
        }
        if (!isWhite() && white) {
            properties |= Cat.WHITE;
        }
        System.out.println(properties + "finally");
    }

    /**
     * 这只猫白吗?请在此处使用位运算读取properties,得到猫是否白的结果
     *
     * @return 白则返回true,否则返回false
     */
    public boolean isWhite() {
        return (properties & Cat.WHITE) != 0;
    }

    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setCute(true);
        cat.setFat(true);
        cat.setWhite(false);
        System.out.println("这只猫萌吗:" + cat.isCute());
        System.out.println("这只猫胖吗:" + cat.isFat());
        System.out.println("这只猫白吗:" + cat.isWhite());
    }
}