第 8章 对象的初始化和清理
在 Java中一切皆为对象,所以在涉及到初始化和清理时必然提及对象,即对象的初始化和对象的清理。对象的初始化完成对象初始状态的设定,如初始化一些参数,构造一个新的对象等。对象的清除涉及到内存的操作,即对象在不使用时必须有适当的机制释放该对象占用的内存,否则内存中累积的对象很快会耗尽内存资源。
Java在创建一个新对象时引入了构造函数的概念,并且在对象清除中引入了,垃圾回收器,,垃圾回收器可以自动释放系统不再使用的内存资源,从而不会出现内存泄露的问题,相比于 C++语言而言更安全,程序员在编写代码时不必考虑释放资源的代码,垃圾回收器完成内存资源释放工作。本章讨论对象的初始化和对象的清理,本章的知识点会显得零散,但是认真研究每节所讨论的问题,会对初始化和清理有一个完整而清晰的认识。
8.1 构造函数
构造函数是 Java中一种特殊的函数,通过构造函数可以顺利的完成对象的初始化工作,当创建一个新的对象时,Java首先调用构造函数确保对象得到适当的初始化。
构造函数与普通函数有不同之处:
( 1)构造函数没有返回值,其实也不需要返回值,虽然创建对象时确实返回了对象引用,但是构造函数本身不允许返回任何数据类型。
( 2)构造函数的名称必须和其相应的类具有相同的名字,大小写完全一样。因为构造函数的调用是 Java完成的,所以必须让编译器知道如何找到构造函数,而编译器在加载类时就已经知道了构造函数的,样子,了,所以很容易在类中找到该函数而初始化一些参数。
( 3)构造函数在每次创建新对象时被编译器自动调用。
代码是带有构造函数的类的例子。
8.1.1 默认构造函数
默认构造函数是用户没有定义的情况下,系统自动调用的构造函数,任何一个类在创建新对象时都是需要构造函数完成初始化的,如果用户没有定义构造函数,编译器就认为用户同意按照系统默认的方式构造该对象了。但是这个调用用户看不见,是系统的内部行为。是潜在的一种函数调用。
代码默认构造函数的示例程序可以说明这种情况。
代码 默认构造函数示例
1 class Tree{
2 public void setHeight(){
3 System.out.println(“set the height of the
tree!”);
4 }
6 }
7 public class SimpleConstructor{
5 public static void main(String[] args){
4 //创建新对象,并赋予对象引用 tree,此时调用默认构造函数
11 Tree tree = new Tree();
12 tree.setHeight();
13 }
14 }
8.1.2 自定义构造函数
Java提供了另一种构造函数的定义方式,即用户自定义的构造函数。这种思想很容易理解,对象的创建一定满足需求,而对象的初始化自然不能千篇一律的按照固定的模式。这样用户依据需求分析设计的类在初始化时自然具有多样性。用户自定义的构造函数分为有参数的构造函数和无参数的构造函数。
Java也允许一个类具有多个构造函数,在创建对象时编译器根据构造函数的参数类型和参数个数来分辨调用哪个构造函数(这里涉及到函数重载的概念),代码展示了一个类具有多个构造函数的情况。
如代码 默认构造函数示例
1 class Tree{
2 int treeheight ;
3 Tree(){ //创建无参数构造函数
4 System.out.println(“初始化无参数 Tree”);
5 }
6 Tree(int height){ //创建有参数构造函数,参数设置 Tree的高度
7 treeheight = height;
8 System.out.println(“初始化有参数 Tree”);
9 }
10 public static void main(String[] args){
11 new Tree(); //创建 Tree对象,系统调用无参数构造函数
12 new Tree(12); //创建 Tree对象,系统调用有参数构造函数
13 }
14 }
8.2 函数的重载
函数是对象的行为特性,或者说是一种动作,为函数起名字相当于为行为取名字,这样的名字要求具有实际意义,
易于理解和维护。如定义一个读数据库的方法
ReadDataBase(),这样的函数名字就易于理解,也很好的说明了行为的内容是读数据库信息。但是同样的读数据库信息的方法也有区别,如一个系统有多个数据库,有本地数据库和网络数据库,那到底是读本地数据库呢还是读取网络数据库的信息呢,所以为了区别具有相同行为内容却又有差异的函数,Java提供了函数重载的概念。
我们可以设置如上的 ReadDataBase()方法的参数来区分到底读哪个数据库的信息,如果是读取本地数据库的信息,
可以传入一个本地数据库链接的字符串,或不用参数,如果是链接网络数据库可以传入一个网络地址,这样具有同名的方法通过形式参数的不同而实现了方法重载,在构造函数中我们提到过重载的概念,这里通过一个例子说明构造函数重载和普通函数重载的实现。
8.3 数据成员初始化
Java提供了一种安全机制,可以保证所有的数据成员都得到适当得初始化。对于基本类型的数据成员,Java不要求必须为其赋予有意义的初始值,但是为了保证安全性提供了一个默认值,所有的基本类型的数据在被方法调用前都会得以适当的初始化,如果用户没有为数据成员赋值,编译器就使用默认值为其完成初始化。
可以通过代码基本数据初始化示例看到这些默认值。
如代码 基本数据初始化示例
1 class InitValues{
2 int a;
3 short b
4 long c;
5 float d;
6 boolean e;
7 byte f;
8 char g;
9 public static void main(String[] args){
10 System.out.println(“int a,”a);
11 System.out.println(“short b,”+b);
12 System.out.println(“long c,”+c);
13 System.out.println(“float d,”+d);
14 System.out.println(“Boolean e,”+e);
15 System.out.println(“byte f,”+f);
16 System.out.println(“char g,”+g);
17 }
18 }
8.4 static成员的初始化
由 static关键字修饰的成员的初始化与基本类型的数据成员的初始化基本一致。如果 static修饰的是基本类型而没有赋予初始值,就采用默认值。
如果 static修饰的是对象引用,若引用没有类的实例初始化则为 null。该对象引用无法使用。通过下面的例子说明 static成员初始化中需要注意的问题。代码 static成员初始化示例程序。
8.5 对象的清理
Java的对象清理与 C++不同,在 C++中所有的对象清理工作都由程序员自己处理,即编写对应的析构函数释放对象占用的资源,如果程序员没有编写释放资源的代码则肯定会造成内寻泄露。而在 Java中,不再采用这种方式来释放资源,而是采用了垃圾回收机制( GC)实现对象资源的释放,
这就极大的提高了编程的效率,让程序员可以集中精力于问题模型的解决上。
垃圾回收机制在实现对象资源释放时只管理使用 new关键字创建的对象所占用的内存资源。所以,对于其他对象占用的资源垃圾回收机制无法管理,所以严格的说垃圾回收机制可以有效的管理内存资源,保证不发生内存的资源泄露。
但是却无法保证其他资源的泄露,Java提供了一个 finally
关键字,使某些代码总是可以执行来避免其他资源的泄露发生。如果没有 finally,问题会很复杂。这里只要求初学者知道这个问题,至于更具体的解释读者可以自己学习,
可以参考 [美 ]Peter Haggar著的 Practical Java,该书的很多主题对于初学者而言都有很好的指导作用。
8.6 本章习题
学完本章中,读者需要回答:
( 1) 什么叫函数重载? 重载的意义何在? 如何实现函数重载的?
( 2) 详细说明数据成员初始化的方法和数据成员初始化的顺序 。
( 3) Static的含义,在对象的初始化中为什么需要首先初始化 static成员 。
( 4) 创建一个带无参数构造函数的类,并在构造函数中打印一条信息 。 同时为该类创建一个对象 。
( 5) 创建一个带参数的构造函数的类,其接受一个字符串参数,在构造函数中打印这个字符串 。
( 6) 创建一个没有构造函数的类,并在 main()中创建对象,
验证编译器是否真的自动加入了缺省构造函数 。
( 7) 分析代码 8-7中如下代码的执行过程:
56 static MyRoom t3 = new MyRoom();
可以参考对象的创建过程分析。