可以想象为每个类都定义一个initialize()方法,与类同名,让编译器在初始化期间自动调用。确保在你能操作对象之前,它已经被恰当地初始化。
从概念上讲“初始化”和“创建”是彼此独立的,在Java中,“初始化”和“创建”捆绑在一起,两者不能分离。
构造器是一种特殊类型的方法,因为它没有返回值。(new表达式确实返回了对新建对象的引用,但构造器本身并没有返回任何值)。
5.2 方法重载每个重载的方法都必须有一个独一无二的参数类型列表。甚至参数顺序不同也足以区分两个方法。
如果传入的数据类型小于方法中声明的形式参数类型,实际数据类型就会被提升。
5.3 默认构造器如果你的类中没有构造器,则编译器会自动帮你创建一个默认构造器,但是如果已经定义一个构造器,无论是否有参数,编译器就不会帮你自动创建默认构造器。
5.4 this关键字this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用。当需要返回当前对象(class类)的引用时,可以这样返回return this;
有时为了将自身传递给外部方法,可以使用this关键字。另外,如果参数s的名称和数据成员s的名称相同,可以使用this.s来代表数据成员(类属性)就能解决。
class Apple{
Apple getPeeled(){
return Peeler.peel(this);
}
}
class Peeler{
static Apple peel(Apple apple){
// 这个apple就是上面Apple的this
return apple;
}
}
5.5 在构造器中调用构造器
除构造器外,编译器禁止在其他任何方法中调用构造器。
尽管可以用this调用一个构造器,但却不能调用两个,此外,必须将构造器调用置于最起始处,否则编译器报错。
5.6 清理:终结处理和垃圾回收一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一垃圾回收动作发生时,才会真正回收对象占用的内存。
- 对象可能不被垃圾回收。
- 垃圾回收不等于“析构”。
- 垃圾回收只与内存有关。
记住,无论是“垃圾回收”还是终结,都不保证一定发生。如果Java虚拟机并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存。
5.7 垃圾回收器如何工作引用计数常用来说明垃圾收集器的工作方式,但似乎从未被应用于任何一种Java虚拟机实现中。引用计数是一种简单但速度很慢的垃圾回收技术,每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加1,当引用离开作用域或被置为null时,引用计数减1。如果对象之间存在循环引用,则会出现“对象应该被回收,但引用计数却不为零”。
在一些更快的模式,并非基于引用计数。它们的依据思想是:对任何“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。
Java虚拟机将采用一种自适应垃圾回收技术,至于如何处理存活对象,取决于不同的Java虚拟机实现。
“停止-复制”,显然这意味着,先暂停程序运行,然后将所有存活对象从当前堆复制到另一个堆,没有被复制的全是垃圾。当到新堆时,它们是一个挨着一个的。效率低,一是因为复制堆需要多一倍的空间,二是垃圾少时仍要复制。
所以一些Java会进行检查:要是没有新垃圾产生,就会转到另一种工作模式“标记-清扫”,一般而言,标记-清扫速度相当慢,当垃圾少时,速度就很快了。
这里讨论的虚拟机中,内存分配一较大的“块”为单位。每个块都用相应的“代数”来记录是否存活,停止-复制方法就会往废弃的块中拷贝对象,当块在某处被引用时,代数增加。垃圾回收器定期清理,大型对象仍然不会被复制(只是代数增加),小对象的块则被清理。如果对象很稳定,就会切换到标记-清扫;同样如果清扫效果不理想,出现很多碎片,就会切换回停止-复制。
自适应的、分代的、停止-复制、标记-清扫。
5.8 成员初始化《深入理解Java虚拟机》中分为:分代、标记-清除、标记-复制、标记-整理算法。
局部变量必须初始化;成员变量可以不初始化。
5.9 构造器初始化所有成员变量早有构造器初始化。初始化的顺序是先静态对象(如果它们尚未因为前面对象创建时被初始化过),而后是“非静态”对象。main()方法是静态方法。
假设有个名为Dog的类,创建过程如下:
- 即使没有显示地使用static关键字 ,构造器实际上也是静态方法。因此,当首次创建类型为Dog地对象时,或者Dog类地静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
- 然后载入Dog.class,有关静态初始化的动作都会执行。因此静态初始化只是在Class对象首次加载的时候进行一次。
- 当用new Dog()创建对象地时候,首先将在堆上为Dog对象分配足够地存储空间。
- 这块存储空间将被清零,这就自动地将Dog对象中所有基本数据类型设成默认值,而引用被设置成null。
- 执行所有出现于字段定义出的初始化动作。
- 执行构造器。
这可能会牵涉到很多动作,尤其是涉及继承的时候,父类静态-子类静态-父类成员-父类构造-子类成员-子类构造。如果存在子类重写父类方法要进一步分析,本质上还是子类在调用super(),执行的是子类重写过的方法。