
5.9 this关键字
在Java中this关键字可能是读者最难理解的了,因为其语法较为灵活,this到底有哪些用处呢?从之前的代码中读者应该已经发现,可以使用this强调本类中的方法,除此之外this还有以下作用:
(1)表示类中的属性。
(2)可以使用this调用本类的构造方法。
(3)this表示当前对象。
5.9.1 使用this调用本类中的属性
在程序中可以使用this调用本类属性。
【例5.43】现在有以下的一个类

在本类中构造方法的目的很明确,就是为类中的属性赋值,但是从构造方法传递的两个参数名称上是很难看出“n表示的意义”或是“a表示的意义”,为了可以清楚地表示参数的意义,将以上的类修改为如下的形式:

此时,从参数的名称上可以很清楚地知道,要传递的第一个参数是姓名,第二个参数是年龄,但是这样一来,又一个新的问题出现了:

类的本意是要将参数传递的name值赋给类中的name属性,把age的值赋给age属性,但是以上程序真的可以达到这样的效果吗?下面来验证一下:

程序执行结果:

从结果中可以发现,姓名为“null”,年龄为“0”,也就是说并没有把从构造方法中传递进去的参数值赋给属性,现在的构造方法并不能成功地把传递进去的值赋值给类中的属性。可见,在赋值的时候属性并不是明确地被指出,所以造成错误,而这种错误可以利用this关键字来解决,代码修改如下:

程序执行结果:

从程序运行结果来看,达到了所需要的目的,而在构造方法之中,因为已经明确地标识出了类中的两个属性:“this.name”和“this.age”,所以在进行赋值操作的时候也不会产生歧义。
说明
提问:之前的代码操作的是哪个属性?
对于上面代码很容易的知道哪个是属性,哪个是参数,但是之前的代码呢:

这里的name和age分别是什么呢?
回答:都是方法中的参数。
实际上以上的“name=name”“age=age”的代码中的两个name和两个age都是构造方法中的参数,这是为什么呢?举例来说:
假设现在一个用户要拿笔写字,摆在此用户面前的有一支笔,离用户10米远的地方还有一支笔,那么如果你是这个用户,你会选择哪支笔?没错,肯定会使用身边的这支笔,因为离得近。
实际上对于程序上也是一样的,在程序的构造方法中已经存在了name和age属性,那么在构造方法中如果要使用name或age属性的话,则肯定要找近的,所以以上的name和age使用的都是构造方法中的参数。
所以,为了方便,建议读者以后在类中访问属性的时候都要加上this关键字。
5.9.2 使用this调用构造方法
如果一个类中有多个构造方法的话,也可以利用this关键字互相调用。
假设现在要求不管类中有多少个构造方法,只要对象一被实例化,就必须打印一行“一个新的Person对象被实例化”的信息出来,很明显,此时如果在各个构造方法中编写此输出语句肯定不合适,所以此时就可以利用this的概念完成。如下面代码。
【例5.44】使用this调用本类的构造方法

程序执行结果:

本程序中提供了两个构造方法,其中有两个参数的构造方法中使用“this()”的形式调用了本类中的无参构造方法,所以即使是通过有两个参数的构造方法实例化,最终结果还是会把对象实例化的信息打印出来。
如果把this()调用无参构造方法的位置任意调换,在任何时候都可以调用构造方法了吗?实际上这样理解是错误的。构造方法是在实例化一对象时被自动调用的,也就是说在类中的所有方法里,只有构造方法是被优先调用的,所以使用this调用构造方法必须也只能放在构造方法的第一行,下面的程序就是一个错误的程序。
【例5.45】错误的代码调用

程序编译时出错:

以上的错误提示就是this()只能放在构造方法的首行。
另外,对于this调用构造方法的时候一定要留一个构造方法作为出口,即程序中至少存在一个构造方法是不使用this调用其他构造方法的。
【例5.46】错误的代码

程序编译时出错:

以上的错误提示为递归调用了构造方法,所以在构造方法间互相调用的时候一定要留一个出口,一般都将无参构造方法作为出口,即在无参构造方法中最好不要再去调用其他构造方法。
5.9.3 this表示当前对象
以上已经为读者讲解了何时使用this调用属性,何时使用this调用方法,实际上在这些特性之外,this最重要的特点就是表示当前对象,在Java中当前对象就是指当前正在调用类中方法的对象。
提示
关于当前对象的解释。
现在假设有张三、李四、王五3个人在谈话,如果现在说话的人是张三,则“当前正在说话的人”就是张三;如果现在说话的人是李四,则“当前正在说话的人”就是李四;依此类推,所以只要是“当前正在说话的人”,那么就表示是当前对象。
【例5.47】观察this表示当前对象

程序执行结果:

从程序的运行结果来看,直接打印对象和调用getInfo()方法打印的结果是一样的,而且在getInfo()方法中永远是一个this关键字,也就是说那个对象调用了类中的方法,则this就表示那个对象。那么这样的一个特性到底有什么用处呢?下面通过一个实例,来分析this表示当前对象的用法。
现在假设有以下的类:

在此类中有name和age两个属性,现在要求产生两个Person对象,并且判断这两个对象是否相等。那么这个时候就会产生以下两个问题。
(1)如何进行对象的比较?
(2)在哪里进行对象的比较?
对于第1个问题实际上从之前讲解String的代码中读者就应该可以了解到,要想进行对象的比较,是必须比较其内容才可以,但是Person中现在并不能使用equals()方法,所以此时就需要对每一个属性进行依次的判断,如果所有属性的内容都相等了,那么就可以证明这两个对象相等,这一点可以通过如下的代码进行验证。
【例5.48】对象比较的第1种方式

程序执行结果:

以上的程序确实完成了两个对象的比较功能,但是一个新的问题又来了,把所有的判断方法放在主方法中合适吗?实际上这也就是之前所提出的第2个问题:“在哪里进行对象的比较?”,读者可以做这样的一个比喻,假如现在有两个人,如果一个人要判断另外一个人和自己是否相等,则肯定由这个人发出比较的请求,即在人这个类中就应该存在与其他人比较的方法。所以,对象比较的方法应该放在Person类之中,而不应该在main()方法中进行编写,修改后的代码如下。
【例5.49】修改后的对象比较操作

程序执行结果:

以上程序Person类中定义了一个compare()方法,此方法的主要功能就是专门完成两个对象的比较操作,在比较时,首先进行地址的比较,如果两个对象的地址一样,则肯定是同一个对象,而如果地址不相等,则将一个个属性进行依次的比较。
注意
对象比较操作。
对象比较操作在开发中是一个重要的概念,在随后的章节部分还将进行介绍,但其基本的操作形式是不变的,所以一定要重点掌握。