
5.4 构造方法与匿名对象

构造方法是在类中定义的一种特殊方法,它在一个类使用关键字new实例化新对象时默认调用,其主要功能是完成对象属性的初始化操作。
提示:关于构造方法的补充说明。
在本章开篇时就为读者讲解了对象实例化定义语法格式,在这样的格式之中就包含有构造方法的调用,现将此格式拆分,并一一为读者解释:“①类名称②对象名称=③new ④类名称()”。
类名称:对象所有的功能必须由类定义,也就是说本操作是告诉程序类所具有的功能。
对象名称:实例化对象的唯一标注,在程序之中利用此标注可以找到一个对象。
new:类属于引用数据类型,所以对象的实例化一定要用new开辟堆内存空间。
类名称():一般只有在方法定义的时候才需要加上“()”,这个就表示调用构造方法。
另外需要提醒读者的是,一旦开始定义构造方法,那么类中就会存在构造方法与普通方法两种方法,区别在于:“构造方法是在实例化对象的时候使用,而普通方法是在实例化对象产生之后使用的。”
在Java语言中,类中构造方法的定义要求如下。
构造方法的名称和类名称保持一致。
构造方法不允许有返回值类型声明。
由于对象实例化操作一定需要构造方法的存在,所以如果在类之中没有明确定义构造方法的话,则会自动生成一个无参数并且无返回值的构造方法,供用户使用;如果一个类中已经明确定义了一个构造方法,则不会自动生成无参且无返回值的构造方法,也就是说,一个类中至少存在一个构造方法。
提示:关于默认构造方法。
在一个类中至少都会存在一个构造方法,在之前所编写的程序中实际上并没有声明构造方法,那么当使用javac命令编译程序时就会自动为类追加一个无参且无返回值的构造方法。
范例:默认情况下会存在一个无参构造方法

正是因为存在有这样的构造方法,所以当实例化对象采用了“new Person()”的时候才不会提示没有无参构造方法的错误信息。
范例:定义构造方法为属性初始化

本程序在Person类中定义了拥有两个参数的构造方法,并且利用这两个构造方法为类中的name与age属性初始化,这样就可以在Person类对象实例化的时候实现name与age属性的赋值操作。
提问:关于类中setter()方法的意义。
在本程序中通过Person类的有参构造方法在类对象实例化的时候,就可以实现name与age属性内容的初始化,这样可以减少setter()方法的调用,以实现简化代码的目的,在这样的情况下类中继续提供setter()方法是否还有意义?
回答:setter()可以实现属性修改功能。
setter()方法除了拥有初始化属性内容的功能之外,也可以实现修改内容的功能,所以在类定义中是必不可少的。
构造方法虽然定义形式特殊,但是其本质依然属于方法,所以构造方法也可以进行重载。不过构造方法重载的时候只需考虑参数的类型及个数即可,而方法名称也一定要和类名称保持一致。
范例:构造方法重载

本程序类中针对Person类的构造方法进行了重载,分别定义了无参构造、单参构造、双参构造,这样在进行对象实例化的时候就可以通过不同的构造方法来进行属性初始化内容的设置。
注意:编写顺序。
在一个类中对构造方法重载时,所有的重载的方法按照参数的个数由多到少,或者是由少到多排列,即以下的两种排列方式都是规范的。

以上的两种写法都是按照参数的个数升序或降序排列,但是以下的写法就属于不规范定义。

当然,编写不规范并不表示语法错误,上面的3种定义全部都是正确的,只是考虑到编码规范才为读者加以说明。而且现在的每个类中有成员属性、构造方法、普通方法,这三者定义的规范顺序:首先定义成员属性;其次定义构造方法;最后定义普通方法。
在对象实例化定义格式中,关键字new的主要功能是进行堆内存空间的开辟,而对象的名称是为了对该堆内存的引用,这样不仅方便使用堆内存同时防止其变为垃圾空间,也就是说对象真正的内容是在堆内存里面,而有了构造方法之后就可以在堆内存开辟的同时进行对象实例化处理,这样即便没有栈内存指向,该对象也可以使用一次,而对于这种没有指向的对象就称为匿名对象,如图5-9所示。

图5-9 匿名对象
范例:使用匿名对象进行类操作

本程序直接利用“new Person("张三",18)”语句实例化了一个Person类匿名对象并且直接调用了tell()方法,由于没有栈内存的引用指向,所以该对象在使用一次之后就将成为垃圾空间。
提问:对象该如何定义比较好?
现在有了匿名对象和有名对象这两种类型的实例化对象,在开发中使用哪种会比较好?
回答:根据实际情况选择。
首先匿名对象的最大特点是使用一次就丢掉了,就好比一次性饭盒一样,用过一次后直接丢弃;而有名对象由于存在引用关系,所以可以进行反复操作。对于初学者而言,实际上没有必要把太多的精力放在对象类型的选择上,一切的代码开发还是需要根据实际的情况来决定。
在构造方法为属性初始化的过程中,除了可以传递一些数据的参数之外,也可以接收引用数据类型的内容。
范例:使用构造方法接收引用数据类型


本程序实现了Person类与Message类两个类的相互引用,在Person类中需要在构造方法中接收Message类对象,并且将Message类中的info属性取出为name属性赋值,同时也提供有返回新的Message类对象的处理方法以实现返回信息的拼凑处理,本程序的内存引用分析如图5-10所示。

图5-10 程序内存引用分析