× 如何确保对象的初始化?Java的做法是,在对象创建时自动调用类的构造方法,之后,用户才能得到对象的句柄。
× 为了让编译器知道类中的那个方法是构造方法,Java沿用C++的做法,构造方法的名称与类名相同。
× new表达式确实会返回新创建的对象的reference,但构造方法不能写入任何返回值语句,这是语法规定的。
× 绝大多数人类语言都有冗余,即使省掉几个字也能判断出他在讲什么,因为我们可以从上下文作出判断。
× 构造方法也能重载(override)。Primitive数据在重载的方法中作为实参时,编译系统决定调用那个方法,有一定的依据。体味下面的代码:
public class OverloadTest{
public OverloadTest(byte x){ System.out.println("this is a byte"); }
public OverloadTest(int x){ System.out.println("this is a int"); }
public static void main (String[] args){
OverloadTest ot = new OverloadTest(12);
}
}
× 只要定义了类的构造方法,编译器就不会自动合成默认的的构造方法。
× this关键字只能用于类的方法的内部,它负责返回调用这个方法的对象的reference。
× 在类的构造方法里能调用另一个构造方法。在构造方法中,可以使用this.construct Method(X…)的形式调用其他构造方法。调用构造方法中,构造方法调用语句必须放在方法体的最前端。
× static方法没有“this”(因为调用static方法时调用的是类的方法而不是对象的),所以在static方法中如果出现this关键字,编译系统就会报错。
类的static方法只能访问本类中的其他static方法和static数据成员。但是,在类的static方法体中,实例化一个类后再调用这个对象的方法,这当然是合法的。
× 对象不一定会被垃圾回收器回收,所以,finalize()方法不一定会被调用。例如,在内存够用的情况下,垃圾回收机制永远都不会被启动,这是因为考虑到垃圾回收是有系统开销的。
垃圾回收机制的唯一目的就是将那些程序不再使用的对象所占的内存恢复出来。所以,一切与垃圾回收相关的活动,包括我们写的finalize()方法,都必须与内存及内存释放有关。
Finalize()方法释放的绝对不该是使用new创建的对象所占的内存,一般情况下,如果在java程序里调用了非java程序的方法,这时,在fianlize()方法里要使用native method清除所占的内存。所以,一般不需要写finalize()方法。在特殊情况下,例如,在方法中打开文件写入内容,在垃圾回收之前应该先关闭这个文件,这是,就体现出了finalize()方法的价值。
不能直接调用finalize()方法。
记住,垃圾回收和finalize()方法都是靠不住的,只要JVM还没到快要耗尽内存的地步,它是不会浪费时间来回收垃圾以恢复内存的。
在方法中可以使用System . gc()语句来强制进行垃圾回收。
× 成员的初始化:
1、 Java保证变量在使用之前已经进行了初始化。
对于在方法内部定义的局部primitive变量,这种保障表现为编译时的错误信息。
对于类的primitive成员,Java保证这些成员在使用之前都会获得一个初始值。这是因为类的任何方法都可能初始
化这个数据,如果在每个方法内都对类成员变量初始化不太现实。
2、对于类的成员变量的初始化,可以在定义这些成员变量时就提供初始化值,可以直接赋值,也可以调用方法来赋值。注意,不能“向前引用”(forward referencing),如下所示是不合法的:
class CInit {
int j = g(i);
int i = f();
//...
}
使用构造方法实现类成员变量的初始化,能带来更大的灵活性。但是,这并不排除自动的初始化,它在构造方法在被调用之前就已经完成了。
3、初始化的顺序:
在类内,变量的初始化会优先于任何方法(包括构造方法)。变量的初始化顺序是由各个变量在类内定义的顺序决定的。
Static类成员只会在需要的时候才进行初始化(如:创建第一个类的实例、第一次访问static成员),之后,再创建类的实例,static成员不会再进行初始化了。
如果一个类没有实例化过第一个对象,那么第一次初始化时会先初始化其static成员,再处理非static成员。
4、对创建对象的总结:
a、第一次创建类的对象或者第一次访问类的static方法或字段时,java解释器会搜寻classpath找到类的class文件;
b、java解释器装载class文件,对所有的static成员初始化;
c、使用new语句创建新对象时,先在堆里为对象分配足够的内存,先将这块内存清零,自动将对象的primitive类型的成员赋缺省值,将reference设成null;
d、执行定义成员数据时所作的初始化(赋值);
e、执行构造方法;
5、在类内可以使用static子句,把静态初始化子句组织起来:
class Spoon {
static int i;
static {
i = 47;
}
}
6、类似上面的static子句,对类内的非static变量,可以使用块语句来进行初始化:
Mug c1;
Mug c2;
{
c1 = new Mug(1);
c2 = new Mug(2);
System.out.println("c1 & c2 initialized");
}
这种语法为匿名内部类的初始化提供了必不可少的支持。
× 语句int[] a2;只是得到了一个数组的reference,而这个数组的内存(数组中各个元素所占的内存)还没有分配。对数组来说,初始化可以在程序的任何地方进行。
可以在创建数组的时候进行初始化:int[] a1 = { 1, 2, 3, 4, 5 };
数组相互赋值时复制的是reference。
所有的数组都有一个可供查询的内部成员length,但是不能人工修改。
× 多维数组的创建:
int[][][] a2 = new int[2][2][4];
int[][][] a3 = new int[rand.nextInt(7)][][];
for(int i = 0; i < a3.length; i++) {
a3[i] = new int[rand.nextInt(5)][];
for(int j = 0; j < a3[i].length; j++)
a3[i][j] = new int[rand.nextInt(5)];
}