当前位置 : 主页 > 编程语言 > 其它开发 >

[Java编程思想] 第五章 初始化与清理

来源:互联网 收集:自由互联 发布时间:2022-05-30
初始化与清理、对象的初始化过程 第五章 初始化与清理5.1 用构建器确保初始化   可以想象为每个类都定义一个initialize()方法,与类同名,让编译器在初始化期间自动调用。确保在你
[Java编程思想] 第五章 初始化与清理 初始化与清理、对象的初始化过程 第五章 初始化与清理 5.1 用构建器确保初始化

  可以想象为每个类都定义一个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()方法,并且在下一垃圾回收动作发生时,才会真正回收对象占用的内存。

  1. 对象可能不被垃圾回收。
  2. 垃圾回收不等于“析构”。
  3. 垃圾回收只与内存有关。

  记住,无论是“垃圾回收”还是终结,都不保证一定发生。如果Java虚拟机并未面临内存耗尽的情形,它是不会浪费时间去执行垃圾回收以恢复内存。

5.7 垃圾回收器如何工作

  引用计数常用来说明垃圾收集器的工作方式,但似乎从未被应用于任何一种Java虚拟机实现中。引用计数是一种简单但速度很慢的垃圾回收技术,每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加1,当引用离开作用域或被置为null时,引用计数减1。如果对象之间存在循环引用,则会出现“对象应该被回收,但引用计数却不为零”。

  在一些更快的模式,并非基于引用计数。它们的依据思想是:对任何“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。

  Java虚拟机将采用一种自适应垃圾回收技术,至于如何处理存活对象,取决于不同的Java虚拟机实现。

  “停止-复制”,显然这意味着,先暂停程序运行,然后将所有存活对象从当前堆复制到另一个堆,没有被复制的全是垃圾。当到新堆时,它们是一个挨着一个的。效率低,一是因为复制堆需要多一倍的空间,二是垃圾少时仍要复制。

  所以一些Java会进行检查:要是没有新垃圾产生,就会转到另一种工作模式“标记-清扫”,一般而言,标记-清扫速度相当慢,当垃圾少时,速度就很快了。

  这里讨论的虚拟机中,内存分配一较大的“块”为单位。每个块都用相应的“代数”来记录是否存活,停止-复制方法就会往废弃的块中拷贝对象,当块在某处被引用时,代数增加。垃圾回收器定期清理,大型对象仍然不会被复制(只是代数增加),小对象的块则被清理。如果对象很稳定,就会切换到标记-清扫;同样如果清扫效果不理想,出现很多碎片,就会切换回停止-复制。

  自适应的、分代的、停止-复制、标记-清扫。

《深入理解Java虚拟机》中分为:分代、标记-清除、标记-复制、标记-整理算法。

5.8 成员初始化

  局部变量必须初始化;成员变量可以不初始化。

5.9 构造器初始化

  所有成员变量早有构造器初始化。初始化的顺序是先静态对象(如果它们尚未因为前面对象创建时被初始化过),而后是“非静态”对象。main()方法是静态方法。

  假设有个名为Dog的类,创建过程如下:

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

  这可能会牵涉到很多动作,尤其是涉及继承的时候,父类静态-子类静态-父类成员-父类构造-子类成员-子类构造。如果存在子类重写父类方法要进一步分析,本质上还是子类在调用super(),执行的是子类重写过的方法。

上一篇:机器学习实战 | XGBoost建模应用详解
下一篇:没有了
网友评论