zxbyhcsdn

           

          關(guān)于this和super有必要理解清楚的地方

          關(guān)于this和super又必要理解清楚的地方!重要的,多態(tài)的關(guān)鍵

          二話(huà)不說(shuō),先來(lái)一段代碼,比較短,需要付出一點(diǎn)點(diǎn)耐心(估計(jì)一上來(lái)就是代碼,又會(huì)趕走很多人吧.....)

          //父類(lèi)
          class FatherClass {
              public int value;
              public void f() {
                  this.run();//注意這兒的是this,注意
              }
              public void run(){
                  System.out.println("FatherClass.run():"+this.value);
              }
          }

          //子類(lèi)
          class ChildClass extends FatherClass {
              public int value = 100;
              public void ff() {
                  super.run();//注意這兒的是super,注意
              }
              //重寫(xiě)
              public void run(){
                  System.out.println("ChildClass.run():"+super.value);
              }
          }

          //孫子類(lèi),這兒用了一個(gè)拼音,偷懶一下,記不到那個(gè)孫子的單詞了。寒啊...當(dāng)初還過(guò)四級(jí),現(xiàn)在忘光光
          class SunziClass extends ChildClass {
              public int value = 200;
              //再次重寫(xiě)
              public void run() {
                  System.out.println("SunziClass.run():"+super.value);
              }
          }

          //這兒是調(diào)用的Main
          public class TestInherit {
                public static void main(String[] args) {
                          FatherClass fc = new ChildClass();
                          fc.f();
                          FatherClass fc1 = new SunziClass();
                          fc1.f();
                          ChildClass cc = new SunziClass();
                          cc.ff();
               }
          }

          想一想運(yùn)行結(jié)果,注意那個(gè)this和super。有點(diǎn)暈頭把,不要暈,穩(wěn)住!自己想一下結(jié)果,然后再來(lái)看運(yùn)行結(jié)果。

          運(yùn)行結(jié)果如下:
          ChildClass.run():0;
          SunziClass.run():100;
          FatherClass.run():0;

          估計(jì)有不少人會(huì)大吃一驚!其他不吃驚的人可以散了!吃驚的人繼續(xù)看下面的。

          this代表什么?這兒代表New出來(lái)的那個(gè)玩意兒在堆空間的引用地址
          對(duì)于下面的這一句:
          FatherClass fc1 = new SunziClass();
          fc1這個(gè)變量里面放的就是this,是new SunziClass()這個(gè)玩意兒在堆空間的引用地址.
          只是這兒fc1是定義成FatherClass,只有FatherClass的屬性和方法是可見(jiàn)的,不過(guò)這不是本文討論的重點(diǎn).

          所以說(shuō)在父類(lèi)里面寫(xiě)的this其實(shí)就是這個(gè)父類(lèi)或者他的子類(lèi),孫子類(lèi),曾孫子類(lèi)... 在運(yùn)行的時(shí)候[重復(fù)一次哈,運(yùn)行的時(shí)候runtime], New 子類(lèi)()或者New 孫子類(lèi)()或者New 曾子類(lèi)()或者....的堆空間的引用地址.
          [再重復(fù)一次,FatherClass里面的this,子類(lèi)里面的this...都是一樣的,指向New出來(lái)的那玩意兒的引用地址]

          很神奇哈!!嘿嘿,這個(gè)其實(shí)就是 多態(tài)的體現(xiàn),也是多態(tài)的實(shí)現(xiàn)基礎(chǔ).看父類(lèi)或者接口定義了方法調(diào)用的邏輯,子類(lèi)可以根據(jù)需要改變算法! 這樣就可以將關(guān)注的方面分為兩個(gè)層面,一:關(guān)注方法調(diào)用的業(yè)務(wù)邏輯[做什么],二:關(guān)注方法的實(shí)現(xiàn)[怎么做].  "做什么和怎么做",這玩意兒好像在軟件工程里面比較眼熟哦!!!!

          問(wèn)題分解了,而且可復(fù)用性也大大提高了.

          好了,this總結(jié)完了,好像越說(shuō)越暈了... 再穩(wěn)一下,看看Super

          下面再來(lái)說(shuō)super
          說(shuō)之前,分析一下內(nèi)存多,這個(gè)圖,挖卡,蜘蛛網(wǎng)來(lái)也....




          現(xiàn)在看這兩句:
          ChildClass cc = new SunziClass();
          cc.ff();
          這兒SunziClass里面沒(méi)有重寫(xiě)父類(lèi)ChildClass的ff方法,
          所以是執(zhí)行的父類(lèi)ChildClass的ff方法.這個(gè)方法里面有一個(gè)super.Run();
          這兒實(shí)際上就執(zhí)行到了FatherClass的Run()方法.

          這說(shuō)明什么啦.
          說(shuō)明super只是記錄對(duì)象內(nèi)部的父類(lèi)的特征(屬性和方法)的一個(gè)引用
          (注意哈:這兒super不是指向父類(lèi)對(duì)象的引用地址哈,new出來(lái)的玩意兒才在堆里面分配空間有引用地址,這兒沒(méi)有去new一個(gè)父類(lèi)對(duì)象哈,只是執(zhí)行了父類(lèi)的構(gòu)造函數(shù)將父類(lèi)的特征生成了,但是屬于New出來(lái)的那個(gè)子類(lèi)對(duì)象)
          估計(jì)上面這段話(huà)也夠暈人了...

          實(shí)踐一下,你可以寫(xiě)
          public FatherClass getThis()
          {
              return this;
          }
          編譯通過(guò),沒(méi)有任何問(wèn)題
          但是你寫(xiě)
          public FatherClass getSuper()
          {
              return super;
          }

          嘿嘿,編譯出錯(cuò)! 為什么啦,
          因?yàn)閟uper并不是一個(gè)堆空間里面的一個(gè)對(duì)象的引用地址,而this才是堆空間里面的一個(gè)對(duì)象的引用地址
              super只能在對(duì)象內(nèi)部使用,而this可以在對(duì)象內(nèi)部使用也可以返回出對(duì)象外.
              super是死的,編譯的時(shí)候就定死了super的指向了,而this是活的,在運(yùn)行時(shí)候決定其指向.

          再說(shuō)一下,子類(lèi)實(shí)例化對(duì)象,并沒(méi)有去實(shí)例化他的父類(lèi)對(duì)象,也就是說(shuō),那個(gè)子類(lèi)對(duì)象里面并沒(méi)有一個(gè)父類(lèi)對(duì)象,
          那你說(shuō)沒(méi)有父類(lèi)對(duì)象,為什么子類(lèi)構(gòu)造函數(shù)要執(zhí)行父類(lèi)的構(gòu)造函數(shù)啦,那是因?yàn)樾枰獎(jiǎng)?chuàng)建父類(lèi)的特征賦予子類(lèi),但是是由子類(lèi)所有,而super就是用來(lái)區(qū)別是是否是父類(lèi)對(duì)象的特征的.
          重寫(xiě)父類(lèi)方法屬性,就是再創(chuàng)建了一個(gè)子類(lèi)的特征,當(dāng)你用this的時(shí)候,就覆蓋了父類(lèi)的特征了,但是父類(lèi)特征還在那兒,用super就能訪(fǎng)問(wèn)道,但是只能在對(duì)象的內(nèi)部使用.對(duì)象外面就只能看到覆蓋了父類(lèi)特征的子類(lèi)特征了.

          寫(xiě)完收工,我Cao,寫(xiě)了2個(gè)小時(shí).....
          其實(shí)寫(xiě)了這么一大堆,就是一句:"this是當(dāng)前對(duì)象在堆空間的引用地址,super是當(dāng)前對(duì)象的父類(lèi)特征的引用"

          有什么不同的見(jiàn)解歡迎討論...共同進(jìn)步!!!

          posted on 2008-07-21 15:35 zxbyh 閱讀(1638) 評(píng)論(11)  編輯  收藏 所屬分類(lèi): J2se

          評(píng)論

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-21 16:34 隔葉黃鶯

          前面代碼跨度太大,看了有些累,用
          public void f(){
          this.run();//注意這兒的是this,注意
          }

          能緊縮一下,看提眼不會(huì)這么渾。
          Java中的實(shí)例方法都是虛的,調(diào)用實(shí)例方法總隱藏 this 引用。
          其實(shí)就是要死咬住一點(diǎn),不管調(diào)用在方法棧怎么來(lái)轉(zhuǎn)來(lái)轉(zhuǎn)去,this 代表著誰(shuí)不能丟了就好理解了。  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-21 16:42 zxbyh

          好了,緊縮了,呵呵
            回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-21 23:34 fwy

          ChildClass cc = new SunziClass();
          cc.ff();
          ----------
          最后執(zhí)行到Father類(lèi)里面的
          public void run(){
          System.out.println("FatherClass.run():"+this.value);
          }
          這里面的this是引用的Sunzi對(duì)象,為什么this.value卻是Father的默認(rèn)value值0呢?  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-22 10:59 隔葉黃鶯

          這樣解釋吧,深入到虛擬機(jī)這一層,方法的調(diào)用常用以下兩個(gè)指令:

          invokevirtual
          invokespecial

          顧名思義,看到 virtual,應(yīng)該能想到虛方法的調(diào)用,也就是動(dòng)態(tài)綁定,以當(dāng)前實(shí)例的真實(shí)類(lèi)型來(lái)決定調(diào)用哪個(gè)實(shí)例的方法。

          而 invokespecial,卻比較古板,它是由實(shí)例的引用類(lèi)型來(lái)決定調(diào)用哪個(gè)方法。

          Java 中的實(shí)例初始化方法<init>,基本可以等同于 this,私有方法和 super所調(diào)用的方法是采用 invokespecial 指令的,也就是根據(jù)引用類(lèi)型決定調(diào)用的目標(biāo)方法。

          其他更多時(shí)候是用 invokevirtual 指令,不細(xì)究這個(gè)了。希望以上的說(shuō)明能幫助大家的理解。  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方[未登錄](méi) 2008-07-22 13:41 zxbyh

          ChildClass cc = new SunziClass();
          cc.ff();
          ----------
          最后執(zhí)行到Father類(lèi)里面的
          public void run(){
          System.out.println("FatherClass.run():"+this.value);
          }
          這里面的this是引用的Sunzi對(duì)象,為什么this.value卻是Father的默認(rèn)value值0呢?
          ------------------------------------------------------------
          這兒實(shí)際上在Sunzi類(lèi)里面是覆蓋了父類(lèi)的Public int value 成員變量了,一般來(lái)說(shuō)應(yīng)該設(shè)置成一個(gè)Private 成員變量,然后寫(xiě)getter和setter來(lái)訪(fǎng)問(wèn).

          一般不推薦直接覆蓋父類(lèi)的Public 成員變量,這個(gè)在C#里面是編譯不能通過(guò)的.
          Java里面能通過(guò),但是出現(xiàn)這樣匪夷所思的結(jié)果. 我也不知道是怎么回事情了,
          難道調(diào)用方法的this和調(diào)用成員變量的this不是一個(gè)??好像不可能啊??
          那位高手幫忙解釋一下啦??  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-22 14:36 zxbyh

          困惑了半天,
          然后看到這一篇文章頓時(shí)茅塞頓開(kāi):
          http://www.sudu.cn/info/html/edu/jsp/20071109/102484.html

          原來(lái)對(duì)象的成員變量在Java里面是允許override的.
          但是成員變量是在編譯的時(shí)候決定,但是方法是在運(yùn)行時(shí)決定.
          方法可以動(dòng)態(tài)綁定,但是成員變量不可以動(dòng)態(tài)綁定,如果要讓成員變量實(shí)現(xiàn)動(dòng)態(tài)綁定,那么就需要通過(guò)方法.

          還是上面那段代碼,在Main方法里面加上如下
          FatherClass fc1 = new SunziClass();
          fc1.f();
          //加上下面的這一段話(huà):
          System.out.println(fc1.value);
          System.out.println(((SunziClass)fc1).value);

          運(yùn)行結(jié)果是:
          0
          200


          怪不得C#里面不允許Override成員變量
            回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-22 16:56 隔葉黃鶯

          很顯然你應(yīng)該規(guī)避這種問(wèn)題的出現(xiàn),既然父類(lèi)中有一個(gè)公有的屬性,子類(lèi)就應(yīng)該直接繼承這個(gè)屬性,再次聲明一個(gè)同名的公有屬性的意義何在。

          這種問(wèn)題可能也就能拿來(lái)做面試題,不過(guò)我找工作都不愿意做筆記題的,心里抵制這種面試方式。  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方[未登錄](méi) 2008-07-22 21:31 zxbyh

          個(gè)人還是覺(jué)得Java應(yīng)該不允許override public成員變量.
          直接讓他編譯不能通過(guò)還還好點(diǎn)...

          腦袋想大了都想不出這樣有何意義,既然是不規(guī)范的東西,何不盡早不讓他發(fā)生.
          就像C#那樣,編譯都通不過(guò)!!  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-22 22:53 fwy

          @zxbyh
          你好,我還是沒(méi)能理解最后
          System.out.println("FatherClass.run():"+this.value);
          this確實(shí)是Sunzi對(duì)象,this.value是如何找到Father里面的value的?

            回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-23 12:40 zhuxing

          寫(xiě)的挺不錯(cuò)的,就是有點(diǎn)亂~_~
          再重新組織一下思路  回復(fù)  更多評(píng)論   

          # re: 關(guān)于this和super有必要理解清楚的地方 2008-07-25 00:58 stanleyxu

          Your example makes beginners really confused. Because you showed a bad logic, why a FatherClass variable should create an ChildClass instance. I suggest you use vehicle, auto, suv, truck, etc.  回復(fù)  更多評(píng)論   


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(1)

          隨筆分類(lèi)

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 东丰县| 金门县| 光山县| 黄龙县| 宜川县| 平和县| 尉犁县| 宿州市| 信丰县| 永昌县| 乐陵市| 宜昌市| 天柱县| 类乌齐县| 靖远县| 乃东县| 天峨县| 南雄市| 舞阳县| 砀山县| 深水埗区| 耿马| 东莞市| 江安县| 巴林左旗| 共和县| 耒阳市| 安泽县| 湄潭县| 紫金县| 灵寿县| 上思县| 同江市| 南岸区| 英吉沙县| 诏安县| 大悟县| 浪卡子县| 张家川| 邯郸县| 宣化县|