有時會遇到this做爲返回值的狀況,那麼此時返回的究竟是什麼呢?html
返回的是調用this所處方法的那個對象的引用,讀起來有點繞口哈,有沒有想起小學語文分析句子成份的試題,哈哈。測試
一點點分析的話,主幹是「返回的是引用」;this
什麼引用呢?「那個對象的引用」;spa
哪一個對象呢?「調用方法的那個對象」;code
調用的哪一個方法呢?「調用的是this所位於的方法」;這樣就清楚了。htm
再總結一下就是,this做爲返回值時,返回的是調用某方法的對象的引用,這個方法正是包含「return this;」這行命令的那個方法;更簡單點說,就是誰調用返回的就是誰。因爲返回的是對象引用,因此this不能用在靜態成員方法中,只能在非靜態成員方法中出現。對象
爲了更清楚、直觀的理解問題,下面以簡單的例子說明。blog
做者: 蟬蟬內存
請尊重做者勞動成果,轉載請在標題註明「轉載」字樣,並標明原文連接:class
http://www.cnblogs.com/chanchan/p/7812166.html
追加(11.26):
添加了下面5項測試代碼:
(1).子類對象調用父類中返回this的方法,該方法未被子類重寫
(2).子類對象調用父類中返回this的方法,該方法已被子類重寫,且返回值類型與父類返回值類型一致
(3).父類對象引用指向子類對象時,即向上轉型時,父類對象引用調用未被子類重寫的返回this的方法
(4).向上轉型時,父類對象引用調用被子類重寫的返回this的方法,且返回值與父類返回值類型一致
(5).向上轉型時,父類對象引用調用被子類重寫的返回this的方法,且返回值類型爲父類返回值類型的子類
分析見後文
(11.26)
包human中定義了Person類、Student類及測試類TestMain,其中Student是Person的子類。
Person類代碼以下:
package human; public class Person { String name; int age; public Person() { } public Person(String n, String g) { name = n; gender = g; } //test:this做返回值 Person reThis1() { Person per = new Person("lu","female"); System.out.println("reThis1 per:" + per.name); return this; } Person reThis2() { Person per = reThis1(); System.out.println("reThis2 per:" + per.name); return this; } Person reThis3() { name = "ma"; return this; } static void equRefer(Person per1, Person per2) { if(per1 == per2) System.out.println("per1指向的對象沒有改變,仍與per2指向同一個對象"); else System.out.println("per1指向的對象已改變,與per2指向不一樣的對象"); System.out.println("per1:" + per1.name); System.out.println("per2:" + per2.name); } public static void main(String[] args) { Person per1 = new Person("liu","female"); Person per2 = per1; per1 = per1.reThis1(); Person.equRefer(per1, per2); per1 = per1.reThis2(); Person.equRefer(per1, per2); System.out.println("調用reThis3以前,per1.name=" + per1.name); per1 = per1.reThis3(); System.out.println("調用reThis3以後,per1.name=" + per1.name); } }
Student類代碼以下:
package human; public class Student extends Person { String stuNumber; int score; public Student(String n, String g) { super(n,g); } Person reThis1() { Person per = new Person("luPS","female"); System.out.println("reThis1 per S:" + per.name); return this; } Student reThis2() { Person per = reThis1(); System.out.println("reThis2 per S:" + per.name); return this; } }
TestMain類以下:
//http://www.cnblogs.com/chanchan/p/7812166.html
package human; public class TestMain { public static void main(String[] args) { Person per1 = new Person("liuP","female"); Person per2 = per1; Person per3; Person per4; Student stu1 = new Student("liuS","female"); Student stu2 = stu1; //追加2017.11.25 per1 = stu1.reThis3(); if( per1 == stu1 ) System.out.println("per1與stu1指向同一個子類對象"); else System.out.println("per1與stu1指向不一樣的對象"); per1 = stu1.reThis1(); if( per1 == stu1 ) System.out.println("per1與stu1指向同一個子類對象"); else System.out.println("per1與stu1指向不一樣的對象"); per3 = stu1; per4 = per3.reThis3(); if( per4 == per3 ) System.out.println("per4與per3指向同一個子類對象"); else System.out.println("per4與per3指向不一樣的對象"); per3 = stu1; per4 = per3.reThis1(); if( per4 == per3 ) System.out.println("per4與per3指向同一個子類對象"); else System.out.println("per4與per3指向不一樣的對象"); per3 = stu1; stu1 = (Student) per3.reThis2(); //向下轉型 if( stu1 == per3 ) System.out.println("stu1與per3指向同一個子類對象"); else System.out.println("stu1與per3指向不一樣的對象"); } }
輸出結果以下:
1 reThis1 per:lu 2 per1指向的對象沒有改變,仍與per2指向同一個對象 3 per1:liu 4 per2:liu 5 reThis1 per:lu 6 reThis2 per:liu 7 per1指向的對象沒有改變,仍與per2指向同一個對象 8 per1:liu 9 per2:liu 10 調用reThis3以前,per1.name=liu 11 調用reThis3以後,per1.name=ma
追加(11.26)
輸出結果以下:
1 per1與stu1指向同一個子類對象 2 reThis1 per S:luPS 3 per1與stu1指向同一個子類對象 4 per4與per3指向同一個子類對象 5 reThis1 per S:luPS 6 per4與per3指向同一個子類對象 7 reThis1 per S:luPS 8 reThis2 per S:maP 9 stu1與per3指向同一個子類對象
(11.26)
逐句分析執行過程:
(1).第1句:Person per1 = new Person("liu","female");
建立一個Person對象,將name初始化爲「liu」,gender初始化爲「female」,並讓per1指向該對象。
(2).第2句:Person per2 = per1;
定義一個Person類的對象引用,並與per1指向同一個對象;具體內存分配見圖1:
(3).第3句:per1 = per1.reThis1();
由per1調用reThis1()方法,並將返回值賦給per1;reThis1()方法體內定義了一個局部變量per,並建立一個對象,由per指向它;具體內存分配見圖2:
緊接着輸出reThis1 per:lu;最後返回this,並把返回的值賦給per1。
(4).第4句:Person.equRefer(per1, per2);
調用equRefer(per1,per2)來驗證per1的值並未改變;根據下面的輸出結果也可知per1仍與per2指向原來的對象,也就是說此時this的值與per1的值是一致的;也能夠說,誰調用的返回的就是誰。
輸出結果:
per1指向的對象沒有改變,仍與per2指向同一個對象
per1:liu
per2:liu
此時的內存圖如圖3:
(5).第5句:per1 = per1.reThis2();
per1調用reThis2(),由(4)可推測,此時per1的值也不會變,是由per1調用的this所處的方法,因此返回的也是per1;具體來分析的話,reThis2()定義了一個局部變量per,並給其賦值爲reThis1(),也就是說reThis2()調用了reThis1(),由(3)、(4)可推知,此時的內存結構是下面這樣的:
局部變量per指向的對象與per1是一致的,由於調用reThis1的對象是per1所指的對象,因此返回值也是per1。
此處的輸出結果爲:
reThis1 per:lu
reThis2 per:liu
(6).第6句:Person.equRefer(per1, per2);
驗證上面的結論,per1指向沒變,此時的內存分配圖如圖4所示:
(7).第七、八、9句:
System.out.println("調用reThis3以前,per1.name=" + per1.name);
per1 = per1.reThis3();
System.out.println("調用reThis3以後,per1.name=" + per1.name);
per1調用reThis3();reThis3()中修改了namer的值,由"liu"改成"ma",而後返回this。
調用先後的內存結構分別如圖六、圖7所示:
輸出結果:
調用reThis3以前,per1.name=liu
調用reThis3以後,per1.name=ma
再一次驗證了上述的結論。
追加(11.26)
結果分析:
從結果能夠看到,返回值與調用方法的對象引用是一致的,是指向同一個子類對象的;
也就是說,即便是由子類來調用父類的返回this的方法,不論子類有沒有重寫該方法,返回值都是指向調用該方法的子類對象的;
當由指向子類對象的父類對象引用來調用返回this的方法時,一樣的,返回值也都指向了 調用該方法的 父類對象引用 所指向的子類對象;
當子類重寫了父類的返回this的方法時,且返回值類型是父類返回值類型的子類,這時返回值同上,不過這裏涉及到向下轉型,代碼中已標出,有疑問能夠參考筆記15。
綜上,這些狀況下也適用「誰調用返回誰」。
(11.26)
關於爲何使用this,我是這麼理解的:因爲定義類的時候還沒有建立對象,因此不能肯定對象到底叫什麼,就用this來統一表示,等到具體調用時就能夠知道對象的名字了,而後就用對象的引用替換this;因此爲了便於記憶,能夠理解成誰調用返回的就是誰。
至於返回this有什麼意義,個人理解是:記返回this的方法爲A,可能A的方法體中對對象的屬性作了某些操做或調用了某些方法完成了某些動做,總之,作完這些操做後就把原對象的引用返回,返回後的狀態是對象最新的狀態,可能與對象調用方法A前不一樣。