首页 理论教育 Java程序设计:this引用的使用

Java程序设计:this引用的使用

时间:2023-11-01 理论教育 版权反馈
【摘要】:根据this出现位置的不同,this作为对象的默认引用有两种情形。实例化对象调用成员时,this引用用来指向调用该方法的对象。在Java中,this关键字有如下三种常见用法。在一个类的构造方法内部,也可以使用this关键字引用其他的构造方法,这样可以降低代码的重复度。由于是新建对象在调用构造方法,因此,MyCircle2构造方法栈帧中持有隐藏局部变量this引用指向该对象,参数radius接收实参的值,被赋值为2.5。

Java程序设计:this引用的使用

在有参构造方法中,引入了一个关键字this。在Java中,this关键字总是指向调用该方法的对象。根据this出现位置的不同,this作为对象的默认引用有两种情形。

(1)系统自动调用构造方法时,this引用用来指向该构造方法正在初始化的对象。

(2)实例化对象调用成员时,this引用用来指向调用该方法的对象。

在Java中,this关键字有如下三种常见用法。

(1)使用this关键字引用成员变量,解决与局部变量名称冲突问题。例如:

按照Java语言的变量作用范围规定,参数age的作用范围为构造方法或方法内部,成员变量age的作用范围是类的内部,这样在构造方法中存在变量age的冲突。Java语言规定,当变量作用范围重叠时,作用域小的变量覆盖作用域大的变量。因此,在构造方法中,参数age起作用,如果需要访问成员变量age则必须使用this进行引用。当然,如果变量名不发生重叠,则this可以省略。但是,为了增强代码的可读性,一般将参数的名称和成员变量的名称保持一致。

(2)在一个类的构造方法内部,也可以使用this关键字引用其他的构造方法,这样可以降低代码的重复度。

构造方法是在实例化对象时被Java虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但可以在一个构造方法中使用“this([参数1,参数2,…])”的形式来调用其他的构造方法。使用时注意,这种调用只能出现在构造方法内部的第一行,且只能出现一次。另外,不能在一个类的两个构造方法中使用this互相调用,否则会出现死循环。

(3)在一个方法中通过this关键字访问其他方法、成员变量。

在一个类的内部,成员方法之间互相调用时也可以使用“this.方法名(参数)”来进行引用,只是所有这样的引用中this都可以省略。在使用“this.成员变量”时,如果不存在和局部变量的冲突,也可以省略this前缀。

当一个对象调用成员方法时,在该方法的栈帧的局部变量表里,第一个位置默认保存的就是用于传递方法所属对象实例的this引用。通过类可以在堆内存中构造若干个对象,而方法在类加载时存放在方法区,只有一份。下面通过一个案例分析。

【例3-5】

分析例3-4中MyCircle2Test2.java运行过程中JVM的内存操作(只分析方法区、栈区和堆区)。

(1)当运行My Circle2Test2程序时,就会启动一个JVM进程,通过类加载器将字节码文件MyCircle2Test2.class加载到该JVM内存的方法区,将main()静态方法放在该方法区的静态区,而将构造方法加载在方法区的非静态区,如图3-7所示。

图3-7 加载MyCircle2Test2类文件(www.xing528.com)

(2)JVM根据类名MyCircle2Test2,识别并调用方法区静态区的main方法(程序入口),开始执行main方法。首先,在main线程虚拟机栈开辟main方法栈帧,执行main方法语句“MyCircle2 c=new MyCircle2(2.5);”时,根据赋值运算符“=”左边的MyCircle2类,将MyCircle2.class类文件加载到方法区,在main方法栈帧分配局部变量c(MyCircle2对象引用变量),该引用变量没有默认值,如图3-8所示。

图3-8 在虚拟机栈中分配main方法栈帧

系统根据赋值运算符“=”右边的new关键字,在堆区中为对象开辟空间。假设该对象空间首地址为0x0015,将方法区内对实例变量的定义拷贝一份到对象空间,然后赋默认值,该对象double型实例变量radius的值默认初始化为0.0,接着执行实例初始化。首先显式初始化radius变量为5.0,如图3-9所示。

图3-9 堆中创建对象、默认初始化和显式初始化

接着,系统自动调用构造方法来完成初始化工作。在方法区非静态区找到构造方法MyCircle2(double radius),在该虚拟机栈顶开辟MyCircle2构造方法栈帧。由于是新建对象在调用构造方法,因此,MyCircle2构造方法栈帧中持有隐藏局部变量this引用指向该对象,参数radius接收实参的值,被赋值为2.5。语句“this.radius=radius;”的作用是将栈帧中局部变量radius的值赋给this引用对象中radius实例变量。到此为止,MyCircle2实例初始化工作完成。内存情况如图3-10所示。

图3-10 调用构造方法初始化

构造方法执行结束后,该方法栈帧出栈,栈帧内存被释放。根据赋值运算符,将堆中MyCircle2对象的地址赋给栈区引用变量c;到此为止,语句“MyCircle2 c=new MyCircle2(2.5);”执行完毕。内存情况如图3-11所示。

图3-11 将堆区对象地址赋值给栈区引用变量

(3)当系统执行main方法打印c对象的半径(c.radius)时,通过main栈帧中引用变量c找到堆中该对象,并访问其实例变量radius。

(4)当系统执行main方法打印c对象面积(c.get Area())时,系统在方法区非静态区找到方法get Area(),在栈顶为该方法分配栈帧。由于是变量c引用的对象调用的该方法,于是栈帧局部变量里持有this引用指向该对象。执行语句“double area=0;”时,系统在栈帧分配局部变量area并初始化为0.0。执行语句“area=PI*radius*radius;”时,先计算赋值运算符右边的表达式,系统在方法区的静态区里找到静态变量PI的值,在堆里找到实例变量radius的值,经过计算后将表达式结果赋值给局部变量area。其实,语句“area=PI*radius*radius;”等价于语句“area=MyCircle2.PI*this.radius*this.radius;”。内存情况如图3-12所示。

图3-12 对象调用get Area()方法内存图

当get Area()方法通过return语句将结果返回到main方法调用处后,get Area()方法栈帧被弹出释放,main方法将该对象面积在控制台打印出来。系统继续执行main方法下一条打印c对象周长的语句,不再赘述。最后,当main方法执行完毕后,main方法栈帧也弹出释放,此时main线程结束。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈