Java中采用了构造器,并额外提供了“垃圾回收器”。对于不再使用的内存资源,垃圾回收器能自动将其释放。
1 用构造器确保初始化
在Java中通过提供构造器,类的设计者可确保每个对象都会得到初始化。创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造器。
构造器采用与类相同的名称。
例如:
new Rock(); // new表达式返回了对新建对象的引用
将会为对象分配存储空间,并调用相应的构造器。
在Java中,“初始化”和“创建”捆绑在一起,两者不能分离。
2 方法重载
构造器是强制重载方法名的一个原因。因为你可能会想用多种方式创建一个对象。
为了让方法名相同而形式参数不同的构造器同时存在,必须用到方法重载。
每个重载的方法都必须有一个独一无二的参数类型列表。
①涉及基本类型的重载
由于 基本类型能从一个“较小”的类型自动提升至一个“较大”的类型,涉及重载时,可能会造成一些混淆。
如果传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会提升。
char byte short int long float double
优先匹配刚好对应得形式参数类型,如果没有则扩大,然后匹配。(优先与它最近的数据类型匹配)
char型略有不同,如果无法找到恰好接受char参数的方法,就会把char直接提升至int型。
如果传入的实际参数的数据类型“较大”,就得通过类型转换来执行窄化转换。如果不这样做,编译器就会报错。
②在构造器中调用构造器
在构造器中,如果为this添加了参数列表,这将产生对符合此参数列表的某个构造器的明确调用。
尽管可以用this调用构造器,但却不能调用两个。此外,必须将构造器调用置于最起始处,否则编译器会报错。
除构造器之外,编译器禁止在其他任何方法中调用构造器。
③static的含义
static方法就是没有this的方法,在static方法的内部不能调用非静态方法。因为它没有把“所操作对象的引用”作为参数传递给当前方法。所以在内部就不能通过this关键字 调用“调用方法的那个对象”的引用。
可以通过传递对象的引用到静态方法里,这就就可以调用非静态方法和访问非静态数据成员了。通常要达到这样的效果,只需要写一个非静态方法即可。我猜测是返回一个当前对象的引用,作为参数传递到静态方法了。
3 清理: 终结处理和垃圾回收
Java有垃圾回收器负责回收那些无用对象占据的内存资源。但也有特殊情况,假定你的对象(并非使用new)获得了一块“特殊”的存储区域,由于垃圾回收器只知道回收那些经由new分配的内存,所以它不知道该如何释放该对象的这块”特殊“内存。
为了应对这种情况,Java允许在类中定义一个名为finalize()的方法。它的工作原理“假定”是这样:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
可finalize方法并没有它看起来这么有用。因为只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序执行结束,并且垃圾回收器一直都没有释放你创建的任何对象的存储空间,则随着程序的退出,那些资源也全部交还给操作系统。
无论是“垃圾回收”还是“终结”,都不保证一定会发生。如果Java虚拟机(JVM)并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存的。
finalize()可以用来做对象终结条件的验证。
例如:
public class FinalizeValidate{
private boolean check = false;
public FinalizeValidate(boolean check){
this.check = check;
}
void checkIn(){
check = false;
}
protected void finalize(){
if(check)
//当对象被终结时,check必须为false,否则会提示(作为对象终结条件的验证)
System.out.println("Error:check");
}
}
class TerminationCondition{
public static void main(String[] args){
FinalizeValidate fv = new FinalizeValidate(true);
fv.checkIn(); //正确操作
new FinalizeValidate(true);
//未执行上一步正确操作;
System.gc();
}
}
/*
执行结果:
Error:check
*/
4 构造器初始化
无法阻止自动初始化的进行,它将在构造器被调用之前发生。
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布在方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
①静态数据初始化
无论创建多少个对象,静态数据都只占用一份存储区域。static不能运用于局部变量,因此它只能作用于域。
只有在第一个对象呗创建或者第一次访问静态数据的时候,它们才会被初始化,此后,不会再被初始化。
初始化的顺序是先静态对象(如果它们尚未因前面的对象创建过程而被初始化),而后是“非静态”对象。
②对象创建的过程(假设有个名为Dog.class的类)
1,即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首先创建类型为Dog的对象时,或者Dog类的静态方法/静态域首次被访问时,
Java解释器必须查找类路径,以定位Dog.class文件。
2,然后载入Dog.class(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
3,当用new Dog() 创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
4, 这块存储空间会被清零,这就自动地将Dog对象中的所有基本数据类型都设置成了默认值,而引用则被设置成了null。
5,执行所有出现于字段定义处的初始化动作。
6,执行构造器。