分类:
2008-09-11 10:36:57
第四章 初始化于清理
方法重载
涉及基本类型的重载
如果插入的数据类型(实际参数类型)“小于”方法中声明的形式参数类型,实际数据类型就会被“提升”。例如如果传入的类型是int,但是方法的参数类型是double,那么,插入的参数就是被“提升”为double。char行略有不同,如果无法找到瞧好接受char存书的方法,就会把char直接提升int型。
如果传入的实际参数“较大”,就得载圆括号里写上类型名称,作必要的类型转换。例如传入的类型为float,而方法的参数类型为int,那么必须进行类型转换,(int)float如果不这样作,编译器就会报错。
以返回值区分重载方法
void f(){}
int f(){}
如果有一行程序为 f();此时Java不能理解调用的是哪一个f(),所以根据方法的返回值来区分重载方法是行不通的。
static方法没有this的方法。
清理:终结处理和垃圾回收
1)对象可能不被垃圾回收
2)垃圾回收并不等于“析构”
3)垃圾回收只与内存有关
假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些由new分配的内存,所以它不知道该如何释放该对象的这块“特殊”内存。为了应对这种情况,Java允许载类中定义一个名为finalize()方法。它的工作原理“假定”是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且载下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
之所以要有finalize(),是由于载分配内存时,可能采用了类似C语言的做法,而非Java的通常做法。在非Java代码中,也许会调用C的malloc()函数系列来分配存储空间,而且除非电泳了free(),负责存储空间将得不到释放,从而造成内存泄漏。所以需要杂ifinalize()本地方法调用它。
System.gc()用于强制进行终结动作(在写程序的时候这么作可以加速调试过程)。
垃圾回收器如何工作
C++像一个院子,里面每个对象都负责管理自己的地盘。一段时间以后,对象可能被销毁,但地盘必须加以重用。
Java虚拟机中,堆的实现截然不同,它更像一个传送带,每分配一个新对象,它就往前移动一格。这移位着对象存储空间的分配数度非常快。Java的“堆指针”知识简单地移动到尚未分配的区域,其效率比得上C++堆栈分配空间的效率。事实上Java的堆未必完全像传送带那样工作。要真是那样的话,势必会导致频繁的内存页面调度(这极大地影响性能),并最终耗尽资源。其中的秘密在于垃圾回收器的介入。当它工作时,将一面回收空间,一面是堆这的对象紧凑排列,这样“堆指针”就可以很容易移动到更靠近传送带的开始处,也就尽量避免了页面错误。通过垃圾回收器对对象重新排列,实现了一种告诉的、有无限空间可供分配的堆模型。
成员初始化
指定初始化(在C++不能这样做)
class InitialValues{
boolean b = true;
char c = 'x';
......
}
构造器初始化
1.初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布在方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。例如:
import com.bruceeckel.simpletest.*;
// When the constructor is called to create a
// Tag object, you'll see a message:
class Tag {
Tag(int marker) {
System.out.println("Tag(" + marker + ")");
}
}
class Card {
Tag t1 = new Tag(1);
Card() {
// Indicate we're in the constructor:
System.out.println("Card()");
t3 = new Tag(33); // Reinitialize t3
}
Tag t2 = new Tag(2);
void f() {
System.out.println("f()");
}
Tag t3 = new Tag(3); // At end
}
public class OrderOfInitialization {
static Test monitor = new Test();
public static void main(String[] args) {
Card t = new Card();
t.f(); // Shows that construction is done
monitor.expect(new String[] {
"Tag(1)",
"Tag(2)",
"Tag(3)",
"Card()",
"Tag(33)",
"f()"
});
}
} ///:~
2.静态数据的初始化
静态初始化只有在必要时刻才会进行。如果不创建Table对象,也不引用Table.b1或Table.b2,那么静态的Bow1 b1和b2永远不会被创建。只有在第一个Table对象被创建(或者第一次访问静态数据)的时候,他们才会被初始化。此后,静态对象不会再次被初始化。
初始化的顺序是先“静态”对象(如果他们尚未因前面的对象创建过程而被初始化),而后是“非静态”对象。
import com.bruceeckel.simpletest.*;
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + ")");
}
void f(int marker) {
System.out.println("f(" + marker + ")");
}
}
class Table {
static Bowl b1 = new Bowl(1);
Table() {
System.out.println("Table()");
b2.f(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl b2 = new Bowl(2);
}
class Cupboard {
Bowl b3 = new Bowl(3);
static Bowl b4 = new Bowl(4);
Cupboard() {
System.out.println("Cupboard()");
b4.f(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl b5 = new Bowl(5);
}
public class StaticInitialization {
static Test monitor = new Test();
public static void main(String[] args) {
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
System.out.println(
"Creating new Cupboard() in main");
new Cupboard();
t2.f2(1);
t3.f3(1);
monitor.expect(new String[] {
"Bowl(1)",
"Bowl(2)",
"Table()",
"f(1)",
"Bowl(4)",
"Bowl(5)",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
"f2(1)",
"f3(1)"
});
}
static Table t2 = new Table();
static Cupboard t3 = new Cupboard();
} ///:~
3.静态句子
与其他静态初始化动作一样,代码仅执行一次:但首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时(即便从未生成过那个类的对象)。例如:
|
数组初始化
Java的数组有一个length成员,表示数组的长度。
Java数组有下标越界控制