第四章 初始化清理
1. 重载函数的参数匹配。
a. 传入的实际参数类型小于方法中声明的形式参数类型,实际参数的类型就会被提升。但char除外,如果没有恰好接受char的方法,就会把char提升为int。
b. 传入的实际参数类型大于方法中声明的形式参数类型,就得显示的类型转换,否则会报错。但这种窄化转换会丢失信息。
2. 在构造器中调用构造器。
如果一个类中有多个构造器,你可以在一个构造器中调用另一个构造器。
如:
注意事项:
a. 你可以用this调用构造器,但你不能用同样的方法构造两个构造器;
b. 构造器调用必须置于最起始处;
c. 除构造器外,其他任何方法都不能调用构造器。
3. 终结处理和垃圾回收
垃圾回收器只知道释放那些经new分配的内存。对于不用new分配的内存可在类中定义一个finalize()方法清理。它是在垃圾回收器准备回收时被调用。但它并不等于析构。
a. 对象不一定总被回收。(一般只有在内存耗尽时才运行垃圾回收)
b. 垃圾回收并不等于析构。
c. 垃圾回收只与内存相关。
4. 不能将finalize()作为通用的清理方法。
finalize()只用于在分配内存时用了类C的做法,如调用了c/c++的代码,而里面又用了malloc()等函数来分配内存,就得在finalize()方法中调用free()等方法清理。
public class Flower {
int petalCount = 0;
String s = new String("null");
Flower(int petals) {
petalCount = petals;
System.out.println("Constructor w/ int arg only, petalCount= "
+ petalCount);
}
Flower(String ss) {
System.out.println("Constructior w/ String arg only, s=" + ss);
s = ss;
}
Flower(String s, int petals) {
this(petals);
//! this(s); //Can't call two!
this.s = s; //Another use of "this"
System.out.println("String & int args");
}
Flower() {
this("hi", 47);
System.out.println("default constructor (no args)");
}
void print() {
//! this(11); //Not inside non-constructor!
System.out.println("petalCount = " + petalCount + " s = " + s);
}
public static void main(String[] args) {
Flower x = new Flower();
x.print();
}
}
5. 终结条件
终结条件可理解为程序要关闭时必须满足的条件。如一个程序中的一个对象打开了一个文件,那么在程序结束时所有打开的文件应该被关闭。
finalize()方法一个重要的用途就是验证终结条件。
如:
本例所有的Book对象在被当作垃圾回收前都应该被签入(check in)。但在main()中有一本没有。如果没有finalize()来验证条件,这个错误将很难发现。
6. 类的每个基本类型数据成员保证都会有一个初始值
boolean false
char 0
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
7. 类里定义一个对象引用时,如果不将其初始化,此引用就会得null值。
8. 与c++不同,类成员变量可在其定义的地方为其赋值。
9. 构造初始化无法阻止自动初始化的进行,它将在构造器被调用前发生。
class Couunter {
int i;
Counter() {
i = 7;
}
}
这里i 先是0再是7
10. 在类的内部,变量会在任何构造器被调用前得到初始化。
11. 初始化的顺序
初始化的顺序是先"静态"对象再"非静态对象"。
12. 对象的创建过程(假设有个Dog类)
1) 当首次创建类为Dog类的对象时(构造器可看成是静态方法),或者Dog类的静态方法/静态字段首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
2) 然后载入Dog.class。有关静态初始化的所有动作都会执行。因此,静态初始化只在class对象首次加载的时候执行一次。
3) 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。 4)这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了却省值,而引用则被设置成了null。
5) 执行所有出现于段定义处的初始化动作。
6) 执行构造器。
13. 静态子句
Java允许将多个静态初始化动作组织成一个特殊的“静态子句”如:
class Spoon {
static int i;
static {
i = 47;
}
}
像static{}中的代码块就是静态子句。该代码块中的语句只执行一次。
14. 非静态实例初始化子句
和静态子句一样,非静态实例初始化也能写成代码块。如:
Dog d1;
Dog d2;
{
d1 = new Dog();
d2 = new Dog();
}
{}中的就是非静态实例初始化子句。
15. 如果数组里的元素不是基本数据类型,那么必须使用new。否则使用数组中的空引用就会产生“异常”
class Book {
boolean checkedOut = false;
Book(boolean checkOut) {
checkedOut = checkOut;
}
void checkIn() {
checkedout = false;
}
public void finalize() {
if(checkedOut)
System.out.println("Error: checked out");
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
//Proper cleanup
novel.checkIn();
// Drop the reference, forget to clean up
new Book(true);
//Force garbage collection & finalization
System.gc(); //强制进行终结动作
}
}