Java語言this關鍵字用法全面總結

學習Java編程的時候,無論是誰,當學到面向對象這部分內容時都會遇到一個關鍵字:this。很多初學者對這個關鍵字的都會感覺到理解不透,不明白這個神祕的”this”到底表示什麼意思。按照官方正規的解釋,this關鍵字的意義被解釋爲“指向當前對象的引用”。這個解釋非常準確並且很精煉,但它太過學術化了,導致很多初學者有點讀不懂,更談不上深入理解它的意義。本文將用大白話的形式幫助初學Java的小夥伴來深入理解this關鍵字的意義,並且梳理它的各種用法。

其實,我們只要把this理解成”本對象自己的...”就可以了。看到這個解釋,很多人可能更懵了,什麼叫”本對象自己的...”?不要着急,讓我們首先來看一段代碼。

Java語言this關鍵字用法全面總結
在這段代碼中,定義了一個表示”人”的類Person,在Person類中,有3個屬性name、age和height,分別來表示姓名、年齡和身高。在類當中定義了一個構造方法,構造方法中對3個屬性進行了初始化操作。最後定義了一個introduce方法,這個方法能夠打印一個Person對象的姓名和年齡。現在,我們在main方法當中創建一個Person類的對象,並且調用這個對象的introduce方法,代碼如下:

Java語言this關鍵字用法全面總結
愉快的運行一下程序,出來的運行結果是這樣的:

Java語言this關鍵字用法全面總結
通過程序的運行結果我們可以看出,在創建對象的時候,對象的屬性被賦予了正確初始值。這個程序本身非常的簡單,誰都可以理解,但是大家請注意,我們在定義構造方法的時候,把表示姓名、年齡和身高的參數分別命名爲:n、a和h,這種命名的可讀性有點差,爲了提高可讀性,我們把構造方法的參數名稱修改爲name、age和height,如下圖所示:

Java語言this關鍵字用法全面總結
修改之後,再次運行main方法,得到的運行結果變成了這個樣子:

Java語言this關鍵字用法全面總結
爲什麼這一次的運行結果出現了問題呢?就是因爲,修改了構造方法之後,當我們調用構造方法創建對象時,給構造方法所傳遞的3個參數值“張三”、20和178.5最終並沒有賦值到對象的3個屬性中。那麼,既然參數值沒有被賦值到對象的屬性中,它們去了哪裏呢?修改代碼後,構造方法的參數與類所定義的屬性同名,根據”同名情況下,局部變量的優先級更高”原則,在構造方法執行的過程中,虛擬機會把參數值賦給”參數本身”,而不是賦值給對象的屬性!具體來說,就是我們給構造方法的name參數傳遞的值是”張三”,而這個”張三”在構造方法執行的過程中,當運行到”name=name;”這條語句時,並沒有把”張三”賦值給對象的name屬性,而是又重新賦值給了name參數自身。就是因爲”張三”最終沒有被賦值到對象的name屬性中,才導致introduce方法中打印出的name屬性是null。當然,age和height這兩個參數也是同樣的賦值效果。
爲了能夠讓虛擬機明白我們所期望的是:把”張三”這個字符串賦值給對象的name屬性,而不是”再一次”把它賦值給構造方法的參數,就需要把構造方法中的賦值語句做出如下修改:
Java語言this關鍵字用法全面總結
大家來看,這一次,我們在構造方法中,給”=”左邊的屬性前面都加上了this關鍵字,經過修改之後,重新運行main方法,就恢復了正常的運行效果。好,現在我們就來探究一下,加了this關鍵字之後,爲什麼程序能夠”恢復正常”。剛纔我們說過,”this”可以被解釋爲” 本對象自己的...”,按照這個邏輯,”this.name”就可以被解釋爲”本對象自己的name屬性”,所以在執行”this.name=name;”這條語句的時候,虛擬機就會把name參數的值”張三”賦值給對象的name屬性。也就是說在這條賦值語句中,”=”左邊的”this.name”表示對象的name屬性,而”=”右邊的name表示方法的name參數。
講到這裏,有的小夥伴可能會問:”this.name”爲什麼不能被解釋爲”本對象自己的name參數”呢?因爲”參數”這個概念是就某個方法而言的,它相當於某個方法的”局部變量”,只是這個”局部變量”比起在方法中定義的真正的局部變量來講有點特殊,它能夠接收從主調方法中傳遞過來的值。因此,當我們說到”參數”這個概念的時候,都是相對於一個”方法”而不是一個”對象”而言的,所以也就不會有”某個對象的參數”這一說法。因此,”this.name”只能被虛擬機認定爲本對象自己的name”屬性”,絕不會被當作name”參數”。

通過這個例子,希望大家能夠理解this關鍵字的意義。在程序中,所出現的”this.屬性名”是this關鍵字最常見的一種用法,也是我們給大家總結的this關鍵字的第一種用法。既然”this.屬性名”可以被解釋爲”本對象自己的XX屬性”,那麼會不會有”this.方法名”這種用法呢?當然有這種用法,當程序中出現了”this.方法名”這種寫法,就可以被解釋爲調用”本對象自己的XX方法”。來看下面的代碼:
Java語言this關鍵字用法全面總結
這一次,我們給Person類增加了一個”打招呼”的方法叫做greet。在introduce方法當中,就可以通過”this.方法名”的方式來調用這個方法,表示調用的是”本對象自己的greet”方法。這是this關鍵字的第二種用法。當然,在introduce方法中並沒有出現其他對象,所以方法名前面的this關鍵字也可以省略不寫。

既然this關鍵字表示的是本對象自己,所以在代碼中可以直接用this來代表對象自身。比如說,在Ojbect類當中定義了一個equals()方法,這個方法用來比較自身對象與其他對象是不是相等,就直接可以用this來與其他對象做比較。

Java語言this關鍵字用法全面總結
上面這段代碼就是Object類的equals()方法的源代碼,有興趣的小夥伴可以去看看。在代碼中直接用this關鍵字代表對象本身,並且和另一個對象obj做了比較。(關於==這個運算符到底比的什麼,大家可以看我的另一篇博文《你真的掌握了Java語言的"=="運算符嗎?我看未必!》)

其實,this關鍵字還有另外一種很重要的用法,那就是在this關鍵字的後面加上小括號,這樣就表示調用了某個類自身的構造方法,爲了講解這種用法我們再來修改一下Person類。

Java語言this關鍵字用法全面總結
這一次,我們給Person類又增加了一個構造方法。這個構造方法只有2個參數,並且只初始化2個屬性。爲了講述方便,我們把上面的3個參數的構造方法稱之爲”構造方法①”,把下面的2個參數的構造方法稱之爲”構造方法②”。通過觀察不難發現,這兩個構造方法當中前2行代碼是相互重複的,爲了避免這種重複性的代碼出現,我們可以在”構造方法①”當中調用”構造方法②”。調用的方式如下:

Java語言this關鍵字用法全面總結
在”構造方法①”中,通過”this(參數);”的方式調用了”構造方法②”。這就是this關鍵字的又一種用法。很多小夥伴可能不理解,爲什麼要通過這種方式來調用構造方法呢?我們難道不能直接寫一個”Person(name,age);”來調用嗎?這裏必須做出解釋:在Java語言中,一個類的構造方法與類名相同。但是,一個類當中也可以定義一個與類名相同的”普通方法”,換句話說就是:並不是只有構造方法與類名相同,”普通方法”也可以取和類相同的名稱(只不過全世界的程序員都不會這麼幹)。那麼,在這種情況下,編譯器如何區分這個方法是”普通方法”還是”構造方法”呢?很簡單,”普通方法”的名稱前面必須定義返回值類型,而”構造方法”的名稱前面則沒有返回值類型的定義。這樣,編譯器就能夠分得清哪個是”構造方法”,哪個是”和類同名的普通方法”。
定義的時候分得清,但是在調用的時候,都是通過方法名來調用的,這時如何分得清代碼中哪一句調用的是”構造方法”, 哪一句調用的是”和類同名的普通方法”呢?爲了解決這個問題,Java語言規定,在本類中調用構造方法的時候,需要通過”this(參數)”的方式來調用。除此之外,Java語言還規定了這種調用方式所必須遵守的規則。首先,這種”this(參數)”的方式只能在”其他構造方法中”使用,不能在普通方法中用。如果在普通方法中按這種方式使用,將被視爲語法錯誤,如下圖所示
Java語言this關鍵字用法全面總結
可以看到,在普通方法中按這樣的方式調用構造方法會出問題。
其次,在一個構造方法中,用”this(參數)”的形式調用構造方法,”this(參數)”必須寫在主調方法的第一行。第三,不能出現相互循環嵌套調用,也就是說,不能在構造方法①中調用構造方法②,又同時在構造方法②中調用構造方法①,如下圖所示
Java語言this關鍵字用法全面總結
這種相互調用的寫法是絕對不允許的。

接下來我們再來思考兩個問題:首先,在main()方法中執行到”new Person("張三",20,178.5);”這句代碼時,實際上是調用了構造方法①,而構造方法①中又調用了構造方法②,兩個構造方法都被調用到了,那麼在內存中會不會創建兩個Person對象呢?答案是不會,爲什麼呢?原因很簡單:構造方法①中調用了構造方法②,並沒有出現new關鍵字,調用構造方法②僅僅是完成了name和age這兩個屬性的初始化,並不會創建出兩個對象。

我們要思考的第二個問題是:既然Java語言允許”普通方法”的名稱與類名相同,而構造方法也與類名相同,那麼在Person以外的類當中如果寫上了”Person(參數)”這樣的代碼,虛擬機如何判斷所調用的是普通方法還是構造方法呢?答案也很簡單,如果”Person(參數)”的前面出現了new關鍵字,這就說明調用的是構造方法,否則說明調用的是普通方法。

講到這裏,我們就把this關鍵字最常用的幾種用法講完了,其實,this關鍵字在我們編寫內部類代碼的時候,還有一種用途,那就是區分屬性或方法的具體歸屬。我們來看下面的代碼:
Java語言this關鍵字用法全面總結
在這段代碼中,定義了外部類Outter,Outter有一個屬性a,並且Outter中又定義了內部類,在內部類的printA()方法中調用了外部類的a屬性。我們都知道,一個內部類可以直接訪問它所在外部類的屬性和方法。這個特性在我們的上面這段代碼中得到了體現。但是,如果內部類中出現了與外部類同名的屬性或方法時,該如何區分調用的到底是哪個屬性或方法呢?比如說,在Inner類中也出現了a屬性,那麼輸出語句中的a到底是指哪個a呢?很簡單,如果輸出語句中直接寫a,那麼調用的是內部類的a屬性。爲了強調它是內部類的a屬性,我們也可以在a的前面加this關鍵字。如果我們希望調用的是外部類的a屬性,可以用”外部類名.this.a”的方式來調用,如下圖所示:
Java語言this關鍵字用法全面總結
以上我們就把this關鍵字的意義和它的各種用法講完了,簡單總結一下:
1、this:表示自身對象,也就是本對象自己
2、this.屬性名:表示本對象自己的屬性
3、this.方法名:表示本對象自己的方法
4、this(參數)表示本對象自身的構造方法(注:”構造方法”這個概念是相對於”類”而言的,但具體到this(參數)這種用法時,表示”我這個對象自己的構造方法”)
5、外部類名.this.屬性:表示在內部類中調用的是外部類的某個屬性(調用外部類方法亦同)

希望本文能夠幫助初學者深入理解this關鍵字的作用。

如想系統學習Java編程,歡迎觀看我在本站的視頻課程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章