this在Java语言中表示指向当前对象的引用。通过this关键字,对象可以调用到自身的属性、方法以及构造方法。
在4.4小节中定义了带有参数的构造方法,这样就能在创建对象的同时设置它各项属性的初始值。细心的读者已经发现:4.4小节中所定义的构造方法,它的参数命名并不符合规范。如果按照命名规范,表示姓名的参数应该被命名为name而不是n,而表示年龄的参数应该被命名为age而不是a。如果把构造方法的参数名称改为规范命名形式,代码如下:
- Person(String name ,char sex ,int age){
- name = name; //初始化name属性
- sex = sex; //初始化sex属性
- age = age; //初始化age属性
- }
把这个修改了参数名称的构造方法添加到Person类中,接下来调用这个构造方法创建一个Person类对象并打印其各项属性,代码如【例04_04】所示:
【例04_04 使用带参数的构造方法创建对象并打印属性】
Exam04_04.java
- public class Exam04_04 {
- public static void main(String[] args) {
- Person p = new Person("张三",'男',20);
- System.out.println("姓名:"+p.name);
- System.out.println("性别:"+p.sex);
- System.out.println("年龄:"+p.age);
- }
- }
运行程序,可以看到运行结果如图4-8所示:
图4-8 修改后的构造方法不能达到预期效果
从图4-8所示的运行结果中可以看出,Person类对象p的三项属性并没有被实际参数赋值,而是仍然保持了对象属性的原始默认值,这是怎么回事呢?其实原因很简单,就是因为构造方法的3个实际参数的值根本就没有传递给对象的属性。那么,实际参数的值到底传递到哪里了呢?这些实参的值都传递给了参数自身!以构造方法中的如下语句举例:
age = age;
当赋值语句执行后,“=”右边age参数的值并没有传递给对象的age属性,而是仍然传递给了age参数自身。造成这种效果的原因也很简单,就是因为参数和对象的属性的名称相同。Java语言中,当参数(或变量)与对象属性同名时,参数(或变量)会对对象属性产生屏蔽效果。所以虚拟机认为“=”左边的age是指定义在构造方法中的age参数,而不是对象的age属性。
如何才能让虚拟机明确的知道“=”左边的age指的是对象的age属性而不是构造方法的age参数呢?很简单,只要在“=”左边的age加上一个this关键字就可以,代码如下:
this.age = age;
而如果把所有属性都加上this关键字,构造方法就成为了:
- Person(String name ,char sex ,int age){
- this.name = name; //初始化name属性
- this.sex = sex; //初始化sex属性
- this.age = age; //初始化age属性
- }
同理,还可以按照同样的方式修改Person类中只有两个参数的构造方法,修改后的构造方法代码如下:
- Person(String name ,char sex){
- this.name = name; //初始化name属性
- this.sex = sex; //初始化sex属性
- }
在Java语言中,this表示指向当前对象自身的引用。初学Java的读者可以简单的把this关键字的意义理解为“本对象自身的...”。因此,“this.age”就表示“本对象自身的age属性”。而构造方法中的赋值语句如下。
this.age = age;
就表示由参数age给本对象自身的age属性赋值。既然赋值语句中被赋值的一方由方法的参数变成了对象的属性,赋值的效果当然也会发生改变,重新运行【例04_04】,运行结果将会变成如图4-9所示的样子:
图4-9构造方法恢复预期赋值效果
通过【例04_04】可以看出,this关键字可以加在属性的前面,这样的书写形式可以使得对象的属性不被方法中的同名参数(或变量)所屏蔽。当然,属性与方法中任何一个参数(或变量)名称都不相同的情况下,程序员也无需特意在属性的前面添加this关键字。
this关键字还可以添加到方法的前面,具体形式如下:
这种写法表示调用“本对象自己的方法”。如果程序员希望在某个方法中调用本对象的另外一个方法就可以用这种形式。例如,在Person类中定义一个sayName()方法,该方法能够打印对象的name属性,其定义代码如下:
- void sayName() {
- System.out.print("我叫"+name);
- }
同时还在Person类中定义一个完成自我介绍的方法introduce(),该方法可以打印对象的name、sex和age三项属性,代码如下:
- void introduce() {
- System.out.print("我叫"+name);
- System.out.println(",性别"+sex+","+"今年"+age+"岁");
- }
通过观察不难发现:introduce()方法中用来打印name属性的语句:
System.out.print("我叫"+name);
已经在sayName()方法中出现,因此可以调用sayName()方法来代替这条打印name属性的语句,具体调用代码如下:
- void introduce() {
- this.sayName();
- System.out.println(",性别"+sex+","+"今年"+age+"岁");
- }
方法中的“this.sayName()”表明调用的是“本对象自身的”的sayName()方法。其实即使去掉方法名称前面的this关键字而直接书写方法的名称,虚拟机也会知道所调用的就是本对象自身的方法,所以只要不是调用其他对象的方法,都可以省略方法名称前的this关键字。
this关键字的第三个用法是用它来表示构造方法。在4.4小节中,我们给Person类定义了两个带有参数的构造方法。细心的读者已经发现:其中带有3个参数的构造方法中有如下两条语句:
- this.name = name;
- this.sex = sex;
这两条语句所实现的功能与带有2个参数的构造方法Person(String name ,char sex)所实现的功能是完全相同的,它们都是用参数给对象的name和sex这两个属性赋上初始值。很多读者都会想到:这两条语句完全可以用带有2个参数的构造方法Person(String name ,char sex)来代替。由于构造方法与类名相同,于是很多读者按照图4-10所示的方式调用构造方法
图4-10 调用构造方法出现语法错误
从图4-10可以清楚的看到:通过方法的名称来调用构造会出现语法错误。正确调用构造方法的方式是:
例如,在带有3个参数的构造方法中调用带有2个参数的构造方法就可以用图4-11所示方式实现:
图4-11 正确调用构造方法的方式
通过图4-11可以看到:用this关键字代替构造方法的名称可以正确的实现构造方法调用,不会出现之前的语法错误。Java语言中,使用this关键字来表示构造方法是一种特殊语法规则。关于这种语法规则,还有一些知识细节需要读者理解和掌握。
首先,使用“this(参数)”的形式调用构造方法并不能创建对象。前面的章节中曾经讲解过,想要创建一个对象,必须用“new 构造方法(参数)”的形式实现。“this(参数)”的调用形式虽然也调用了构造方法,但只是完成了对象属性初始化的操作,并不会创建出一个新的对象。读者可能会问:既然这种调用形式连对象都没有创建,那又何谈对象属性的初始化呢?
观察图4-11不难发现,“this(参数)”的调用语句出现在Person类的带有3个参数的构造方法中,当从main()方法或其他方法中调用带有3个参数的构造方法时,就会出现如下形式的语句:
new Person("张三",'男',20);
虚拟机执行这条语句时会首先创建一个对象,在对象已经存在的基础上,然后在构造方法内部执行:
this(name,sex);
这样就可以实现对象属性的初始化操作。因此形如“this(参数)”的语句在执行时,对象其实已经存在了。
其次,以“this(参数)”形式调用构造方法的语句仅能出现在类的构造方法当中,不能出现在普通方法中,否则将会出现语法错误。例如,在普通方法sayName()中出现这样的调用形式,会导致如图4-12所示的语法错误:
图4-12 普通方法中以this(参数)调用构造方法
另外,以“this(参数)”的形式调用构造方法的语句只能出现在整个方法的第一行,否则也会出现语法错误,如图4-13所示:
图4-13 this(参数)调用语句未出现于第一行
最后,两个构造方法中不能以“this(参数)”的形式相互调用对方,否则会形成循环调用。例如,两个构造方法以图4-14所示的方式相互调用对方是错误的:
图4-14 相互调用构造方法导致语法错误
以上部分详细讲解了this关键字的意义及各种用法,各位读者务必深入理解并牢牢掌握,因为this关键字在Java语言中有着无可替代的作用,是一个非常重要的知识点。
本章重点讲述了类和对象的概念和相关知识点。在本章当中,以Person类为例详细讲述了如何定义一个类,如何在类中定义属性和方法,什么是方法的重载,什么是构造方法以及this关键字的含义和用法。在本章的各个例子中,我们不断的修改和完善Person类,下面的【例04_05】给出了Person类经过多次修改之后的最终版本,并且展示了如何通过带参数的构造方法创建Person类对象,以及调用该对象的各个方法来完成自我介绍、求两个数之和的操作。
【例04_05 Person类对象的创建和使用】
Person.java
- public class Person {
- String name;//姓名
- char sex;//性别
- int age;//年龄
-
- Person(String name ,char sex ,int age){
- this(name, sex);//调用另一个构造方法初始化name和sex属性
- this.age = age; //初始化age属性
- }
-
- Person(String name ,char sex ){
- this.name = name;
- this.sex = sex;
- }
-
- Person(){
-
- }
-
- //定义2个整数相加的方法
- int add(int a,int b) {
- int r = a+b;
- return r;
- }
-
- //定义2个浮点数相加的方法
- double add(double a,double b){
- double r = a+b;
- return r;
- }
-
- //打印姓名
- void sayName() {
- System.out.print("我叫"+name);
- }
-
- //自我介绍
- void introduce() {
- this.sayName();
- System.out.println(",性别"+sex+","+"今年"+age+"岁");
- }
- }
Exam04_05.java
- public class Exam04_05 {
- public static void main(String[] args) {
- Person p = new Person("张三",'男',20);//创建对象
- p.introduce();//自我介绍
- int r1 = p.add(1, 2);//两int型数字求和
- double r2 = p.add(2.5, 3.5);//两double型数字求和
- System.out.println("两个整数相加结果是:"+r1);
- System.out.println("两个浮点数相加结果是:"+r2);
- }
- }
【例04_05】的运行结果如图4-15所示:
图4-15 【例04_05】运行结果