- Java王者归来:从入门迈向高手
- 洪锦魁
- 2963字
- 2025-02-17 16:14:35
9-1 构造方法
构造方法(Constructor)就是类对象建立完成后,自行完成的初始化工作,例如,当我们为TaipeiBank类建立对象后,初始化的工作应该是将该对象的存款余额设为0。
请参考程序实例ch8_7.java的第8行内容:
TaipeiBank A=new TaipeiBank();
上述类名称是TaipeiBank,当我们使用new运算符然后接TaipeiBank(),注意有“()”存在,其实这是调用构造方法,类中默认的构造方法名称应该与类名称相同。读者可能会想,在设计TaipeiBank类时没有建立TaipeiBank()方法,程序为何没有错误?为何会如此?
9-1-1 默认的构造方法
如果在设计类时,没有设计与类相同名称的构造方法,Java编译器会自动协助建立这个默认的构造方法。
程序实例ch9_1.java:简单说明构造方法。

执行结果
这个程序没有输出。
上述程序没有构造方法,其实Java在编译时会自动为上述程序建立一个默认的构造方法。
程序实例ch9_2.java:Java编译程序为ch9_1.java建立一个默认的构造方法,其实第4和5行就是Java编译程序建立的默认构造方法。

执行结果
这个程序没有输出。
9-1-2 自建构造方法
所谓的自建构造方法就是在建立类时,建立一个和类相同名称的方法,这个方法还有几个特点,分别是没有数据类型和返回值。另外,当Java编译程序看到类内有自建构造方法后,它就不会再建默认的构造方法了。
1.无参数的构造方法
在构造方法中是没有任何参数的。
程序实例ch9_3.java:建立BankTaipei类时增加设计默认构造方法,这个程序主要是建立好对象A后,同时打印A对象的存款余额。

执行结果

2.有参数的构造方法
所谓的有参数的构造方法是,当我们在声明与建立对象时需传递参数,此时这些参数会传给构造方法。
程序实例ch9_4.java:在构造方法中需要传两个整数值,然后执行整数加法和乘法输出。

执行结果

9-1-3 重载
重载(Overload)是同时有多个名称相同的方法,然后Java编译程序会依据所传递的参数数量或是数据类型,选择符合的构造方法处理。其实重载的用法也可以应用在一般类内的方法。在正式用实例讲解前,请先思考我们使用许多次的System.out.println()方法,读者应该发现不论我们传入什么类型的数据,都可以输出适当的执行结果。
程序实例ch9_5.java:认识System.out.println()的重载。

执行结果

其实以上就是因为System.out.println()是一个重载的方法,才可以不论输入哪一类型的数据都可以顺利输出,下面是上述实例的图示说明。

上述重载方法可以增加程序的可读性,也可增加程序设计师与使用者的便利性,如果没有这个功能,就上述实例而言,必须设计5种不同名称的打印方法,造成冗长的程序设计负荷与用户需熟记多种方法的负荷。
1.重载应用于构造方法
程序实例ch9_6.java:将重载应用于构造方法,这个程序的构造方法有三个,分别可以处理含有一个整数参数代表年龄,一个字符串参数代表姓名,两个参数分别是整数代表年龄、字符串代表姓名。建立对象完成后,随即打印结果,下面是本程序的图示说明。


执行结果

在上述执行结果中,如果没有为MyClass类对象的属性建立初值,可参考8-5-2节说明,则编译程序会为字符串变量建立null为初值,为整数变量建立0为初值,所以当只有一个参数时,可以看到第22行输出name的初值是null,第24行输出age的初值是0。
其实建议程序设计时,可以增加一个不含参数的构造方法,这个方法可以设置没有参数时的默认值,这样程序可以有比较好的扩展性。
程序实例ch9_7.java:重新设计ch9_6.java,主要是增加没有参数的默认值,可参考第4~7行,让整个程序使用上更有扩展性。

执行结果

2.重载应用于一般方法
程序实例ch9_8.java:将重载应用于类内的一般方法,这个实例有三个相同名称的方法math,可以分别接受1~3个整数参数,如果只有一个整数参数则x等于该参数,如果有两个整数参数则x等于两个参数的积,如果有三个整数参数x则等于三个参数的积。

执行结果

下面是本程序的说明图示。

3.方法签名
在Java的专业术语中有一个名词是方法签名,这个签名的意义如下:
方法签名=方法名称+参数类型
其实Java编译程序碰上重载时就是由上述方法签名判断方法的唯一性,进而可以使用正确的方法执行想要的结果。若是以ch9_8.java为实例,有下列三个math()方法,所谓的方法签名指的是加粗的部分。

特别须留意的是,方法的返回值类型和方法内参数名称并不是方法签名的一部分,所以不能设计一个方法内容相同只是返回值类型不同的方法当作程序的一部分,这种做法在编译时会有错误产生。另外,也不可以设计方法内容相同只是参数名称不同的方法当作程序的一部分,这种做法在编译时也会有错误产生。例如,如果已经有上述方法了,下面是错误的额外重载。

4.返回值类型不同不是重载的方法
Java语言在重载中不可以更改返回值类型,当作是重载的一部分,因为这会造成程序模糊与错乱。
程序实例ch9_8_1.java:尝试更改返回值类型当作重载,结果是编译时产生错误。

执行结果

5.重载也可以用于main()
在Java程序设计时,也可以将重载应用于main()方法,不过JVM目前只接受main()的参数是“String[ ] args”。
程序实例ch9_8_2.java:测试将重载应用于main()方法。

执行结果

6.重载方法与数据类型升级
在设计重载方法时,可能会碰上传递参数找不到匹配的数据类型,这时编译程序会尝试将数据类型升级,下面是升级的方式图示。

在上述图例中,char可以升级为int、long、float、double,int可以升级为long、float、double。
程序实例ch9_8_3.java:在重载方法中数据类型升级的应用,在此实例中的第12行的A.addition()由于找不到匹配方法,此时第一个参数5是int类型,会被升级为long类型而去执行第2~4行的addition()方法。

执行结果

程序实例ch9_8_4.java:如果在重载中有找到匹配的方法,则不执行数据类型升级。程序第2~4行是int数字加法方法,第5~7行是long数字加法方法,第12行调用addition()时,由于已经找到第2~4行是int数字加法方法,所以就不去升级了。

执行结果

如果找不到匹配的方法,而每一个方法都提供相类似的参数可以让数据类型升级,此时会造成模糊而产生错误。
程序实例ch9_8_5.java:在Math类的重载方法中如果个别独立存在都可以提供升级,但是并存时,会造成模糊而产生编译时的错误。

执行结果

9-1-4 this关键词
在8-7-4节中在设计一般方法时有提到名称遮蔽的概念,当类内的方法所定义的局部变量与类的成员变量(也可称属性)相同时,方法会以局部变量优先。在这个环境下,如果确定要存取类的成员变量时,可以使用this关键词,如下:
this.成员变数
以上概念也可以应用在构造方法。若是以ch9_6.java为实例,它的第一个构造方法如下。

其实上述将局部变量设为a,从程序设计观点看最大缺点是程序不容易阅读,如果将局部变量设为age,整个设计如下所示。

程序变得比较容易阅读,但是上述会发生名称遮蔽现象造成错误,在这时就可以使用this关键词,如下所示。

上述语句不仅语法正确,同时程序容易阅读。
程序实例ch9_9.java:使用this关键词重新设计ch9_6.java,在该程序中为了区分成员变量和局部变量,使用了不同名称,这个程序将用this关键词,因为局部变量与成员变量的名称相同,整个程序应该更容易阅读。

执行结果
与ch9_6.java相同。
this的另外一个用法是,可以使用它调用另一个构造方法,特别是在构造方法中有一部分设置已经存在另一个构造方法了,这时可以调用另一构造方法,省略这部分的构造。这个用法的主要观念是让整个程序的设计具有一致性,可以避免太多设置造成疏忽而产生不协调。
程序实例ch9_10.java:先看没有用this关键词调用另一个构造方法的执行结果,假设要建立NBA球员数据,使用两个构造方法,一个是建立球员姓名,另一个是同时建立年龄与姓名,下面是这个程序设计。

执行结果

上述第2行是随意默认NBA的平均年龄,重点是第8行其实所做的事情和4~6行的构造方法相同,这时就可以使用this关键词调用构造方法。
程序实例ch9_11.java:重新设计ch9_10.java,在构造方法中使用this调用其他构造方法。

执行结果
与ch9_10.java相同。
上述第8行使用this(name)调用原先第4~6行的NBAPlayers(String name)构造方法。