学习Java时,总会有一些问题需要弄得非常清楚明白,才不至于在写程序的时候犯下各类小错误,这就是本文存在的意义。本文着重于语法细节的查漏补缺,所以不会太全面。在已经能够日常使用Java的情况下参考此文可能更有意义。本文大部分内容来自于Java名著《Thinking in Java》,并将根据看书的进度不断更新。
1. 基本类型
- Java中每种基本类型所占的存储空间大小是固定的。如下表:
基本类型 | 大小 | 最小值 | 最大值 | 包装类型 |
---|---|---|---|---|
boolean | - | - | - | Boolean |
char | 16 bits | Unicode 0 | Unicode 2^16 - 1 | Character |
byte | 8 bits | - 128 | + 127 | Byte |
short | 16 bits | - 2^15 | + 2^15 - 1 | Short |
int | 32 bits | - 2^31 | + 2^31 - 1 | Integer |
long | 64 bits | - 2^64 | + 2^64 - 1 | Long |
float | 32 bits | IEEE754 | IEEE754 | Float |
double | 64 bits | IEEE754 | IEEE754 | Double |
void | - | - | - | Void |
“-“ 代表语言中没有明确指定,编译器自行决定
- 基本类型存储在堆栈(Stack)中,同一个值拥有同一个引用,而对象存储在堆(Heap)中
- 高精度计算使用
BitInteger
类和BigDecimal
类 - 直接定义常量时,加入后缀字符表示类型,使用
L
或l
表示long
(尽量不要使用l
,因为看起来像1
);使用F
或者f
表示float
,使用D
或者d
表示double
- 在直接写整数时,加入前缀表示进制不同,整数默认为十进制,加上前缀
0x
或者0X
表示16进制(0F),加上前缀7)0
表示八进制(0 Integer
和Long
有toBinaryString()
方法将整数转为2进制
2. 成员默认值
一个变量被声明时没有初始化,则具有默认值。
- 类的成员若是基本类型,则默认值如下表,若是对象,则默认为
null
基本类型 | 默认值 |
---|---|
boolean | false |
char | ‘\u0000’(null) |
byte | (byte)0 |
short | (short)0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
需要注意的是局部变量不适用于该默认值,得到的是随机的值,然而在编译过程就不能通过,这也是Java较好的一点(毕竟程序员们不是都自律:)
3. 注释和文档(javadoc)
详细见:How to Write Doc Comments for the Javadoc Tool
- javadoc 只能为
public
和protected
成员进行文档注释
4. 按值传递还是按引用传递
按值传递大概指的是像C/C++这类,在传递给函数参数时复制一份,而不对传入的对象进行修改的函数调用方法。
而在Java中,对象都是指向某个内容的引用,多个对象可以同时引用同一个内容,而没有被引用的内容则会被回收。在传递参数并对参数进行修改时,修改的就是对象指向的引用而非复制一份。
5. 操作符
1. 算术操作符
- 一元加号
+
将把较小类型的操作数提升为int
- 和C/C++中一样,
++
/--
在操作数前,表示先运算再使用,而在操作数后时,则是先使用当前的值,再进行运算
2. 关系操作符
==
和!=
比较的是对象的引用,对于基本类型,由于相同的值拥有相同的引用,所以可以直接比较,而对象之间则不能。某些类重写了equals()
方法可以用于比较对象的内容,比如String
类
3. 逻辑操作符
&&
、||
和!
这三个运算符只能用于boolean
及其包装类短路 使用逻辑操作符时,在按照顺序进行运算时,一旦能够明确整个表达式的值,就不再计算表达式余下的部分了。
如表达式
true && false && true && true
,在运算到 false 的时候就不会继续运算了,比如有一个String
变量str
判空时,直接使用条件str != null && str.isEmpty()
即可。
6. break
和continue
的标签用法
如以下代码所示:
1 | // 标签只能加在外侧迭代上方 |
7. 重载(Override)
为了达到相同的目的,使用同样的方法名,就要使用重载。重载的方法用参数列表的参数数目、参数类型和参数顺序区分(尽量不要使用顺序区分)。
8. 初始化
- 在类的内部,变量定义的先后顺序决定了初始化的先后顺序,即使变量定义在方法之间,它们仍然会在任何方法(包括构造器)被调用之前得到初始化。
- 静态初始化操作只在首次生成该类的对象时,或者首次访问属于该类的静态数据成员时才会被执行一次。
- Java中也有实例初始化语句,用法是使用一个大括号将语句包围,它会在构造器之前调用,这种语法对于匿名内部类的初始化是必须的。
- 数组在初始化时,使用花括号初始化时,最后有一个逗号是合法的,比如
int [] i = {1, 2, 3,};
9. 访问权限控制
- 访问权限控制等级,从最大权限到最小以此为:
public
、protected
、包访问权限(没有关键词)和private
10. final
关键词
- 在修饰基本类型时,表示其值不可变
- 在修饰对象引用时,表示指向的对象不可变,即不能再指向其他对象,但是对象的内容是可变的
- 允许不初始化的
final
(blank final
),但必须在使用前被初始化。 - 修饰方法时,表示不可被子类所覆盖(用final作为内嵌调用的做法已经过时了)
- 类中所有
private
方法都隐式指定为final
,即不可继承(当然,在子类中,声明一个同样的方法是可以的,但并非是继承的,而是全新的方法) - 修饰类时,表示禁止该类被继承,一个
final
类中所有方法都被隐式指定为final
11. 多态(运行时绑定/后期绑定)
- Java中除了
static
和final
方法(private
也是final
的),其他所有方法都是后期动态绑定的。也就是说,使用基类的方法时,只要子类覆盖了该方法,就会调用子类的方法,因为编译器知道了其具体类型。 - 初始化一个对象时,首先将分配给对象的存储空间都初始化为二进制的0,然后先构造根基类,接着依次构造到基类,再按照顺序构造成员,最后调用构造方法。
- 编写构造器时,应当使用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其他方法