`
凌紫冥
  • 浏览: 24525 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java编程思想第四版——第十五天

    博客分类:
  • Java
阅读更多
2012-04-23
121-131/913

Java编程思想第四版——第十五天

5.5.3 终结条件
通常不能指望finalize(),必须创建其他的“清理”方法,并明确的调用它们。
finalize()另一个用法,不依赖于每次都要对finalize()进行调用,这就是对象终结条件的验证。

5.5.4 垃圾回收器如何工作
垃圾回收器提高对象的创建速度有明显的效果。Java从堆分配空间的速度,可以和其他语言从堆栈上分配空间的速度相媲美。
C++的堆——院子,每个对象负责管理自己的地盘,对象被销毁,地盘被重用。
Java虚拟机,堆的实现,像一个传送带,每分配一个新对象,就往前移动一格。这意味着对象存储空间的分配速度非常快。Java的“堆指针”只是简单的移动到尚未分配的区域,效率比得上C++在堆栈上分配空间的效率。在实际过程中在簿记工作方面还有少量额外开销,但比不上查找可用空间开销大。
Java的堆不完全像传送带那样工作,垃圾回收器一面回收空间,一面使堆中的对象紧凑排列。堆指针可以很容易移动到更靠近传送带的开始处,尽量避免了页面错误。通过垃圾回收器堆对象重新排列,实现一种高速的、有无限空间可供分配的堆模型。
引用计数是一种简单但是速度很慢的垃圾回收技术,通常用来说明垃圾收集的工作方式,但从未被应用于任何一种java虚拟机实现中。
更快的模式中,不是基于引用计数计数,依据思想:堆任何“活”的对象,一定能最终追溯到其存活在堆栈活静态存储区之中的引用。
Java虚拟机采用一种自适应的垃圾回收技术,如何处理找到的存活对象,取决于不同的java虚拟机实现。一种:停止-复制(stop-and-copy),空间连续,需要多个空间进行复制转移,适合垃圾多的情况,必须暂停程序,另一种:标记-清扫(mark-and-sweep),空间不连续,不会发生复制,适合垃圾少的情况,必须暂停程序。
自适应技术:自适应的、分代的、停止-复制、标记-清扫式垃圾回收器。

Java虚拟机中有许多附加技术用以提升速度,尤其是与加载器操作有关的,被称为“即时”(Just-In-Time,JIT)编译器的技术。把程序全部或部分翻译成本地机器码(这本来是java虚拟机的工作),程序运行速度因此得以提升。Java HotSpot技术采用惰性评估(lazy cvaluation),即时编译器只在必要的时候才编译代码。从不会被执行的代码不会被JIT所编译。Java HotSpot,代码每次被执行的时候都会做一些优化,执行次数越多,速度越快。

5.6 成员初始化
Java尽力保证,所有变量在使用前都能得到恰当的初始化,对于方法的局部变量,java以编译时错误的形式来贯彻这种保证。
未初始化的局部变量有可能是程序员的疏忽,如果采用默认值可能掩盖这种失误,因此强制程序员提供一个初始值,可能帮助找出程序里的缺陷。
类的数据成员(即字段)是基本类型,每个基本类型数据成员保证都会有一个初始值。
在类中定义一个对象引用时,如果不初始化,此引用会获得一个特殊值null。

5.6.1 指定初始化
直接的:在定义类成员变量的地方为其赋值。(C++中不能这样做)
非基本类型的对象也可以用同样的方法初始化。不初始化就使用,会报空指针的运行时错误。
编译器会恰当的对“向前引用”发出警告。

5.7 构造器初始化
可以用构造器进行初始化,运行时刻,可以调用方法或执行某些动作来确定初值,这为编程带来了更大的灵活性。但要记牢:无法阻止自动初始化的进行,它将在构造器被调用之前发生。
编译器不会强制一定要在构造器的某个地方或在使用它们之前对元素进行初始化,因为初始化早已得到了保证。

5.7.1 初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。

5.7.2 静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。Static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值,如果它是一个对象引用,那么它的默认初始化值就是null。
如果想在定义处进行初始化,采取的方法与非静态数据没什么不同。
静态初始化只有在必要时刻才会进行,如果不创建对象,也不经过类直接引用,那么静态数据永远都不会被创建。只有第一个类对象被创建(或第一次访问静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化。
初始化的顺序是先静态对象(如果他们尚未因前面的对象创建过程而被初始化),而后是“非静态”对象。要执行main()(静态方法),必须加载StaticInitialization类,然后其静态域被初始化。

对象的创建过程,假设有个名为Dog的类:
1. 即使没有显示的使用static关键字,构造器实际上也是静态方法。首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位Dog.class文件。
2. 然后载入Dog.class(这将创建一个Class对象),有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
3. 当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
4. 这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被设置成了null。
5. 执行所有出现于字段定义处的初始化动作。
6. 执行构造器。这可能牵涉很多动作,尤其是涉及继承的时候。

5.7.3 显示的静态初始化
Java允许将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫做“静态块”)。
例如:
public class Spoon{
static int i;
static{
i = 47;
}
}
尽管上面的代码看起来像个方法,但它实际只是一段跟在static关键字后面的代码。与其他静态初始化动作一样,这段代码仅执行一次:当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时(即便从未生成过那个类的对象)。

5.7.4 非静态实例初始化
Java中也有被称为实例初始化的类似语法,用来初始化每一个对象的非静态变量。
实例初始化子句:
{
mug1 = new Mug(1);
mug2 = new Mug(2);
print(“mug1 & mug2 initialized”);
}
看起来和静态初始化子句一模一样,只不过少了static关键字。这种语法对于支持“匿名内部类”的初始化是必须的,但是它也使得可以保证无论调用了哪个显示构造器,某些操作都会发生。实例初始化子句是在构造器之前执行的。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics