概要
这一章的复习主要涵常见的 运算符 及经常用到的 运算符操作 和 关键字。这里整理的都是个人觉得比较重要重新认真分析的东西,不一定全部为基础,如果有不准确的地方,还望大佬从评论区指出,感激不尽。
文章中的所有的自定义的测试都在自己的 java-review 仓库中,本文对应的链接:
操作符
算数运算符
在运算过程中会自动进行类型提升1 | int i = 1; |
算数运算符中重要的就是 + 操作符,以为它支持对 String 的操作用来连接字符串,式子中存在 String 类型的时候,最终类型会被转换为 String 类型,转换时机还是跟运算顺序有关,由结合律决定,详细的 String 会在后面的 String 中细致分析。
等价操作符
== 和 != 等价性操作符对于基本数据类型和对象分开操作
- 基本类型 直接比较数值,例如:
int、double等 - 对象引用 比较引用是否相等,是否指向同一个对象
在 java 的基类 java.lang.Object 的 boolean equals(Object obj) 方法,就是使用了 == 操作符来进行比较是否等价
因此所有的 java 类型调用 equals(obj) 方法的时候,其实就调用了 == 来比较对象的,需要重写 equals(obj) 方法才能按照指定的方式来比较!,String、Integer 等
1 | A a1 = new A(12); |
String 中重写了基类中的 equals(obj) 方法:
- 如果是同一个对象,直接返回
true - 判断是否为
String类型对象 - 判断编码格式是否相同
- 根据编码类型调用对应的比较方法
1 | // java 12 source |
直接常量
指定进制
| format | 进制 |
|---|---|
| 0b10 | 二进制 |
| 100 | 十进制(默认) |
| 0144 | 八进制 |
| 0x64 | 十六进制 |
指定类型
| format | suffix | type |
|---|---|---|
| 1.2F | f / F | float |
| 123L | l / L | long |
在前面有提到整数默认类型为 int,非整数类型默认类型为 double
指数计数
e/E 用来表示 10 的幂次,默认为 double 类型
1 | double d = 1.2e3; |
移位操作符
这部分应该是除了算数运算和比较运算符之外最多的了。
>>操作为 算数左/右移,左边的补位跟符号有关- 正数补
0 - 负数补
1
- 正数补
>>>为逻辑右移,就当做直接右移就完事了。
通常使用的时候使用 >>> 逻辑右移,避免在处理负数上出现状况
1 | int mid = lo + ((hi - lo) >>> 1); |
自动递增和递减
前置递增没有什么特点,主要举例分析后置自动递增操作符的机制。后置递增机制 (递减同理):
- 将 局部变量表中的值 压入 操作数栈 中
- 局部变量表的值
+ 1 - 将结果从 操作数栈 中弹出,并赋值给 局部变量表
1 | // java test |
之所以结果出现 i = 0 ,就是因为后置递增的机制的原因,i 在完成赋值之后又被重复赋值上了保存到 temp 中的原来的值。
将上述机制可以等效为:
因为 java 中不能使用指针,无法完成基本类型传地址对原变量进行修改的操作,所以这里使用 c++ 来完成对上述机制的描述。
1 | // c++ test |
位运算操作符
& 按位与的操作
取最后一个
1表示的值去掉二进制表示中的最后一个
1
1 | // java test |
~ 按位取反运算符
-x = ~x + 1 的证明
1 | // java test |
^ 按位异或操作
^ 的性质就是相同的数进行异或为 0,这个性质就适用于
- 一个数组除了 一个数出现奇数次 外,其他的数都出现了 偶数次,求这个数
操作符优先级
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 | ( ) [ ] |
–> |
| 2 | ! + - ~ ++ -- |
<– |
| 3 | * / % |
–> |
| 4 | + - |
–> |
| 5 | << >> >>> |
–> |
| 6 | < <= > >= instanceof |
–> |
| 7 | == != |
–> |
| 8 | & |
–> |
| 9 | ^ |
–> |
| 10 | | |
–> |
| 11 | && |
–> |
| 12 | || |
–> |
| 13 | ? : |
<– |
| 14 | = += -= *= /= &= |= ^= ~= <<= >>= >>>= |
<– |
关键字
package 关键字
必须是第一条代码import 关键字
编译器遇到 import 关键字会从 classpath 中开始查找对应路径的 .class 文件。
this 关键字
this 当前对象引用
this关键字只 能用于方法中,this代表的是调用当前方法的对象实例方法返回 当前引用本身,参考
StringBuilder中的StringBuilder append(String )1
2
3
4
5
6
7
8// java test
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("A").append("B").append("C").append("D");
System.out.println("str: " + stringBuilder);
///:~ str: ABCDStringBuilder源码分析1
2
3
4
5
6
7
8
9
10
11
12
13
14// java 12 source
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence {
public StringBuilder append(String str) {
super.append(str);
return this; // 返回当前对象引用
}
}this可以用于区分同名的 形参 和 类的成员变量if result 加 成员变量 不加 形参 不使用
this关键字修饰,默认情况下调用的为 形参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
32
33
34
35
36
37
38
39
40
41
42
43// java test
public class This {
private int value;
private This() {}
/*
this 在构造器中调用构造器
1. 必须在第一句
2. 能且只能调用一次
*/
private This(int value) {
this();
this.value = value;
}
private void paramWithoutThis(int value) {
System.out.println("without: " + value);
}
private void paramUseThis(int value) {
System.out.println("useThis: " + this.value);
}
private static void thisObjRef() {
This _this = new This(1);
System.out.println("_this.value: " + _this.value);
_this.paramUseThis(2);
_this.paramWithoutThis(2);
/* Output:
_this.value: 1
useThis: 1
without: 2
*///:~
}
}this()在构造器中调用构造器只能在 构造器中 ,必须 在第一句,能且 只能 调用一次
ClassName.this来引用外部类适用于 外部类的成员变量或者方法 和 内部类 重名的时候ClassName.this用于锁定外部类对象,进而可以调用外部类的成员变量和方法test()和this.test()都会调用当前对象的方法,即内部类对象,所以都是调用了内部类的成员变量和方法
1 | // java test |
static 关键字
- 使用了
static修饰的变量或者方法会独立出来,不会与包含它的类的任何实例对象关联再一起。 static修饰的 方法 和 属性,可以通过全类名.变量名/方法名直接调用
静态和非静态的关系
- 静态方法中不能直接调用非静态的属性属性/方法,只能通过对象实例的引用 来调用 拥有权限的属性/方法
- 非静态的方法中可以直接调用静态的方法
关于 static 和 内部类 的关系会放到后面来分析。
例如下面的测试中,value 属性独立了出来,不和任何一个实例对象相关联,所有的 Static 公用这个属性
1 | // java test |
final 关键字
final 数据
- 适用情况
- 永远不发生改变的常量
- 运行时被初始化的值,而不希望被改变
final修饰的变量同样可以先声明,再初始化- 成员变量必须在
static和final共同修改的域占据一段 不可修改 的存储空间final同样可以用来修饰 形参,这个类似于c++中的const关键字,都是锁定常量为 只读,无法进行修改不管是 基本类型 还是 包装类型,使用了
final关键字修饰以后都 不能进行修改操作
1 | // java test |
final 方法
防止方法覆盖(重写)final 关键字将方法锁定,其导出类中无法对该方法进行重写操作private 关键字修饰方法都是隐式地指定为了 final,无法被重写,给 private 修改的方法添加 final 关键字的是多余的
final 类
禁止继承,不会有任何子类,其内部属性都别隐式地指定为了 final 变量