操作符与控制执行流程

本章主要为 Java 操作符与控制执行流程的相关笔记。

赋值

对基本数据类型的赋值是简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在赋值时,是直接将一个地方的内容复制到另一个地方。例如:对基本数据类型使用 a = b,那么修改 a 的内容,b 不会受到影响。

在对象赋值时,由于是对对象的引用进行操作,所以实际上是将引用复制到另一个地方。例如:对对象使用 c = d,那么 cd 都指向原本只有 d 指向的那个对象。另外,将一个对象传递给方法时,大多数情况下,传递的也是引用。

算术操作符

一元减号和一元加号,都能将较小类型的操作数提升为 int,例如:

1
2
short a = 10;
short b = +a; // Incompatible types. Required: short , Found: int

自动递增和递减

对于前缀递增和前缀递减(如 ++a--a),会先执行运算,再生成值。而对于后缀递增和后缀递减(如 a++a--),会先生成值,再执行运算。例如:

1
2
3
int a = 10;
System.out.println(a++); // 10
System.out.println(++a); // 12

对象的等价性

对于基本类型来说,使用 ==!= 即可。对于对象来说, == 仅仅只是比较对象的引用是否相同。如果想比较两个对象的实际内容,应该使用 equals() 方法。另外,对于自定义的类,需要在类中覆盖 equals() 方法后,才能进行正确的比较。

逻辑短路

当使用逻辑操作符时,我们会遇到一种短路现象,即一旦能够明确无误地确定整个表达式的值,就不再计算表达式余下部分了。

直接常量

位置 符号 含义
后缀 L(l) long
后缀 F(f) float
后缀 D(d) double
前缀 0X(0x) 十六进制
前缀 0 八进制

通过使用 IntegerLong 类的静态方法 toBinaryString() 可以很容易得到对应的二进制数。

在 Java 里,e 代表 10 的幂次,并且默认是 double 类型的。例如:1e2 = 100.0

按位操作符

& | ^
0 & 0 = 0 0 | 0 = 0 0 ^ 0 = 0
0 & 1 = 0 0 | 1 = 1 0 ^ 1 = 1
1 & 0 = 0 1 | 0 = 1 1 ^ 0 = 1
1 & 1 = 1 1 | 1 = 1 1 ^ 1 = 0

按位非(~),取反操作符,属于一元操作符,对操作数按位取反。

1
2
int i = 0;
System.out.println(~i); // -1

按位操作符可与等号(=)联合使用,例如:&=|=^= 都是合法的(由于 ~ 是一元操作符,所以不可与 = 联合使用)。按位操作符还可以对布尔类型进行操作( ~ 除外),同时不会出现短路现象。

移位操作符

移位操作符只可用来处理整数类型。

左移位操作符(<<) 有符号右移位操作符(>>) 无符号右移位操作符(>>>)
低位补 0 符号位正,高位补 0;符号为负,高位补 1 高位补 0

对较小的数据类型进行移位处理,在移位之前会自动转换为 int 类型,并且右操作数只有低 5 位才有用(因为 int 为 32 位,为了避免无意义的移位)。同理,对 long 进行操作,右操作数只有低 6 位才有用。

1
2
3
4
5
6
7
8
9
short i = 2;
i = i << 2; // Incompatible types. Required: short. Found: int.


int i = 16;
System.out.println(i + " : " + Integer.toBinaryString(i)); // 16 : 10000
System.out.println((i << 1) + " : " + Integer.toBinaryString(i << 1)); // 32 : 100000
System.out.println((i << 31) + " : " + Integer.toBinaryString(i << 31)); // 0 : 0
System.out.println((i << 33) + " : " + Integer.toBinaryString(i << 33)); // 32 : 100000

三元操作符

相比 if-else 显得更加简练:

1
2
int n = 10;
System.out.println(n < 100 ? n : 100); // 10

forEach 语法

对于数组和容器,forEach 将自动产生每一项:

1
2
3
4
int[] n = {1, 2, 3, 4, 5};
for (int x : n) {
System.out.println(x);
}

标签

标签必须在迭代语句之前声明,主要用于多重循环:

  • 一般的 continue 会退回最内层循环的开头,并继续执行
  • 带标签的 continue 会达到标签的位置,并重新进入紧接在那个标签后面的循环
  • 一般的 break 会中断并跳出当前循环
  • 带标签的 break 会中断并跳出标签所指的循环
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    outer:
    for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
    System.out.print("[" + i + " " + j + "] "); // [0 0] [0 1] [1 0] [1 1]
    continue;
    }
    }

    outer:
    for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
    System.out.print("[" + i + " " + j + "] "); // [0 0] [1 0]
    continue outer;
    }
    }

    outer:
    for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
    System.out.print("[" + i + " " + j + "] "); // [0 0] [1 0]
    break;
    }
    }

    outer:
    for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
    System.out.print("[" + i + " " + j + "] "); // [0 0]
    break outer;
    }
    }