Java中為什么this可以調(diào)用當(dāng)前實(shí)例
1. 前言
在剛開始學(xué)習(xí)Java的時(shí)候,大家肯定都接觸過this關(guān)鍵字,尤其是在構(gòu)造函數(shù)賦值的時(shí)候,如下示例:
public class Person { private String name; private int age; public Person(String name, int age) { // 必須加this關(guān)鍵字,否則無法完成成員變量的賦值 this.name = name; this.age = age; } }
在構(gòu)造函數(shù)中,如果成員變量名稱和參數(shù)名稱相同時(shí),必須加this關(guān)鍵字,否則你只是將參數(shù)name賦值給它本身,并沒有賦值給Person.name,因?yàn)榫植孔兞康膬?yōu)先級高于成員變量。一旦加上this關(guān)鍵字,由于this指向的是當(dāng)前實(shí)例,就可以完成對象的成員變量賦值。
那為什么可以通過this關(guān)鍵字訪問到當(dāng)前對象呢?
2. 棧幀
要弄清這個(gè)問題,首先要了解JVM在執(zhí)行方法時(shí),方法棧的棧幀結(jié)構(gòu)。
Java虛擬機(jī)以【方法】作為最基本的運(yùn)行單元,【棧幀】就是用于支持JVM進(jìn)行方法調(diào)用背后的數(shù)據(jù)結(jié)構(gòu),它也是JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)中【虛擬機(jī)?!恐械臈T?。
簡單點(diǎn)說,方法的執(zhí)行過程可看作是一個(gè)個(gè)棧幀從入棧到出棧的過程。
棧幀中存儲了方法的:局部變量表、操作數(shù)棧、動(dòng)態(tài)連接和方法返回地址等信息。
當(dāng)使用javac程序?qū)⒃创a編譯成字節(jié)碼后,一個(gè)方法的棧幀需要多大的局部變量表,多深的操作數(shù)棧就已經(jīng)被計(jì)算出來,并且寫入到方法表的【Code】屬性中了,這一切和程序運(yùn)行時(shí)無關(guān)。
換言之,一個(gè)方法它有多少個(gè)局部變量,在編譯時(shí)就已經(jīng)確定,不會(huì)隨著程序的運(yùn)行而改變。今天我們要探究的【this】問題,就在方法棧的局部變量表中。
3. 分析
我們?nèi)匀挥胘avap命令來分析編譯后的Class文件,這是最有說服力的。
public class Person { public void say() { } public static void staticSay() { } }
如上一段代碼,分別有一個(gè)實(shí)例方法和靜態(tài)方法,我們已經(jīng)知道,在靜態(tài)方法中,是無法訪問【this】的,但是在實(shí)例方法中可以。
先javac Person.java再javap -verbose Person,得到的信息有點(diǎn)長,我只貼這兩個(gè)方法的信息。
public void say(); descriptor: ()V flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LineNumberTable: line 8: 0 public static void staticSay(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=0, locals=0, args_size=0 0: return LineNumberTable: line 12: 0
重點(diǎn)關(guān)注【Code】那一欄,say()有一個(gè)局部變量,有一個(gè)參數(shù)。staticSay()沒有局部變量,也沒有參數(shù)。
是不是感到很疑惑?say()方法形參是空的,方法體也是空的,為什么編譯后會(huì)顯示它有一個(gè)局部變量和一個(gè)形參呢?
其實(shí),對于實(shí)例方法而言,它至少有一個(gè)參數(shù)和一個(gè)局部變量,那就是當(dāng)前對象。JVM在調(diào)用對象的實(shí)例方法時(shí),會(huì)將對象本身的引用作為第0號參數(shù)傳遞過去,這樣你就可以通過this關(guān)鍵字訪問到對象本身了,其實(shí)也就是訪問第0個(gè)參數(shù)而已。
如下,這兩個(gè)方法其實(shí)是等價(jià)的。
public void say(Person this, String text) { System.out.println(text); } public void say(String text) { System.out.println(text); }
4. 總結(jié)
Java虛擬機(jī)在執(zhí)行方法時(shí),會(huì)將方法打包成一個(gè)【棧幀】,棧幀中有【局部變量表】,參數(shù)也是局部變量表的一部分,一個(gè)方法的局部變量表有多大在編譯時(shí)就已經(jīng)確定,不會(huì)隨著程序的運(yùn)行而改變。
對于實(shí)例方法而言,在編譯時(shí)會(huì)自動(dòng)加上一個(gè)隱藏的0號參數(shù),就是當(dāng)前類。JVM在調(diào)用對象的實(shí)例方法時(shí),會(huì)自動(dòng)將對象引用作為第0號參數(shù)傳遞過去,訪問【this】其實(shí)就是訪問第0號參數(shù)。
到此這篇關(guān)于Java中為什么this可以調(diào)用當(dāng)前實(shí)例的文章就介紹到這了,更多相關(guān)Java this調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaWeb監(jiān)聽器Listener實(shí)例解析
這篇文章主要為大家詳細(xì)介紹了JavaWeb監(jiān)聽器Listener實(shí)例,針對監(jiān)聽器進(jìn)行進(jìn)行細(xì)致分析,感興趣的小伙伴們可以參考一下2016-08-08SpringBoot使用Thymeleaf自定義標(biāo)簽的實(shí)例代碼
這篇文章主要介紹了SpringBoot使用Thymeleaf自定義標(biāo)簽的實(shí)例代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09ConditionalOnProperty注解的作用和使用方式
在SpringBoot項(xiàng)目開發(fā)中,@ConditionalOnProperty注解允許根據(jù)配置文件中的屬性值來控制配置類是否生效,該注解通過屬性name和havingValue來判斷配置是否注入,如果application.properties中的對應(yīng)屬性值為空或不匹配havingValue設(shè)定值2024-09-09基于Maven骨架創(chuàng)建JavaWeb項(xiàng)目過程解析
這篇文章主要介紹了基于Maven骨架創(chuàng)建JavaWeb項(xiàng)目過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08關(guān)于HttpServletRequest獲取POST請求Body參數(shù)的3種方式
這篇文章主要介紹了關(guān)于HttpServletRequest獲取POST請求Body參數(shù)的3種方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11