zxbyhcsdn

           

          關于this和super有必要理解清楚的地方

          關于this和super又必要理解清楚的地方!重要的,多態的關鍵

          二話不說,先來一段代碼,比較短,需要付出一點點耐心(估計一上來就是代碼,又會趕走很多人吧.....)

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

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

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

          //這兒是調用的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();
               }
          }

          想一想運行結果,注意那個this和super。有點暈頭把,不要暈,穩住!自己想一下結果,然后再來看運行結果。

          運行結果如下:
          ChildClass.run():0;
          SunziClass.run():100;
          FatherClass.run():0;

          估計有不少人會大吃一驚!其他不吃驚的人可以散了!吃驚的人繼續看下面的。

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

          所以說在父類里面寫的this其實就是這個父類或者他的子類,孫子類,曾孫子類... 在運行的時候[重復一次哈,運行的時候runtime], New 子類()或者New 孫子類()或者New 曾子類()或者....的堆空間的引用地址.
          [再重復一次,FatherClass里面的this,子類里面的this...都是一樣的,指向New出來的那玩意兒的引用地址]

          很神奇哈!!嘿嘿,這個其實就是 多態的體現,也是多態的實現基礎.看父類或者接口定義了方法調用的邏輯,子類可以根據需要改變算法! 這樣就可以將關注的方面分為兩個層面,一:關注方法調用的業務邏輯[做什么],二:關注方法的實現[怎么做].  "做什么和怎么做",這玩意兒好像在軟件工程里面比較眼熟哦!!!!

          問題分解了,而且可復用性也大大提高了.

          好了,this總結完了,好像越說越暈了... 再穩一下,看看Super

          下面再來說super
          說之前,分析一下內存多,這個圖,挖卡,蜘蛛網來也....




          現在看這兩句:
          ChildClass cc = new SunziClass();
          cc.ff();
          這兒SunziClass里面沒有重寫父類ChildClass的ff方法,
          所以是執行的父類ChildClass的ff方法.這個方法里面有一個super.Run();
          這兒實際上就執行到了FatherClass的Run()方法.

          這說明什么啦.
          說明super只是記錄對象內部的父類的特征(屬性和方法)的一個引用
          (注意哈:這兒super不是指向父類對象的引用地址哈,new出來的玩意兒才在堆里面分配空間有引用地址,這兒沒有去new一個父類對象哈,只是執行了父類的構造函數將父類的特征生成了,但是屬于New出來的那個子類對象)
          估計上面這段話也夠暈人了...

          實踐一下,你可以寫
          public FatherClass getThis()
          {
              return this;
          }
          編譯通過,沒有任何問題
          但是你寫
          public FatherClass getSuper()
          {
              return super;
          }

          嘿嘿,編譯出錯! 為什么啦,
          因為super并不是一個堆空間里面的一個對象的引用地址,而this才是堆空間里面的一個對象的引用地址
              super只能在對象內部使用,而this可以在對象內部使用也可以返回出對象外.
              super是死的,編譯的時候就定死了super的指向了,而this是活的,在運行時候決定其指向.

          再說一下,子類實例化對象,并沒有去實例化他的父類對象,也就是說,那個子類對象里面并沒有一個父類對象,
          那你說沒有父類對象,為什么子類構造函數要執行父類的構造函數啦,那是因為需要創建父類的特征賦予子類,但是是由子類所有,而super就是用來區別是是否是父類對象的特征的.
          重寫父類方法屬性,就是再創建了一個子類的特征,當你用this的時候,就覆蓋了父類的特征了,但是父類特征還在那兒,用super就能訪問道,但是只能在對象的內部使用.對象外面就只能看到覆蓋了父類特征的子類特征了.

          寫完收工,我Cao,寫了2個小時.....
          其實寫了這么一大堆,就是一句:"this是當前對象在堆空間的引用地址,super是當前對象的父類特征的引用"

          有什么不同的見解歡迎討論...共同進步!!!

          posted on 2008-07-21 15:35 zxbyh 閱讀(1636) 評論(11)  編輯  收藏 所屬分類: J2se

          評論

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

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

          能緊縮一下,看提眼不會這么渾。
          Java中的實例方法都是虛的,調用實例方法總隱藏 this 引用。
          其實就是要死咬住一點,不管調用在方法棧怎么來轉來轉去,this 代表著誰不能丟了就好理解了。  回復  更多評論   

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

          好了,緊縮了,呵呵
            回復  更多評論   

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

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

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

          這樣解釋吧,深入到虛擬機這一層,方法的調用常用以下兩個指令:

          invokevirtual
          invokespecial

          顧名思義,看到 virtual,應該能想到虛方法的調用,也就是動態綁定,以當前實例的真實類型來決定調用哪個實例的方法。

          而 invokespecial,卻比較古板,它是由實例的引用類型來決定調用哪個方法。

          Java 中的實例初始化方法<init>,基本可以等同于 this,私有方法和 super所調用的方法是采用 invokespecial 指令的,也就是根據引用類型決定調用的目標方法。

          其他更多時候是用 invokevirtual 指令,不細究這個了。希望以上的說明能幫助大家的理解。  回復  更多評論   

          # re: 關于this和super有必要理解清楚的地方[未登錄] 2008-07-22 13:41 zxbyh

          ChildClass cc = new SunziClass();
          cc.ff();
          ----------
          最后執行到Father類里面的
          public void run(){
          System.out.println("FatherClass.run():"+this.value);
          }
          這里面的this是引用的Sunzi對象,為什么this.value卻是Father的默認value值0呢?
          ------------------------------------------------------------
          這兒實際上在Sunzi類里面是覆蓋了父類的Public int value 成員變量了,一般來說應該設置成一個Private 成員變量,然后寫getter和setter來訪問.

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

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

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

          原來對象的成員變量在Java里面是允許override的.
          但是成員變量是在編譯的時候決定,但是方法是在運行時決定.
          方法可以動態綁定,但是成員變量不可以動態綁定,如果要讓成員變量實現動態綁定,那么就需要通過方法.

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

          運行結果是:
          0
          200


          怪不得C#里面不允許Override成員變量
            回復  更多評論   

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

          很顯然你應該規避這種問題的出現,既然父類中有一個公有的屬性,子類就應該直接繼承這個屬性,再次聲明一個同名的公有屬性的意義何在。

          這種問題可能也就能拿來做面試題,不過我找工作都不愿意做筆記題的,心里抵制這種面試方式。  回復  更多評論   

          # re: 關于this和super有必要理解清楚的地方[未登錄] 2008-07-22 21:31 zxbyh

          個人還是覺得Java應該不允許override public成員變量.
          直接讓他編譯不能通過還還好點...

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

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

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

            回復  更多評論   

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

          寫的挺不錯的,就是有點亂~_~
          再重新組織一下思路  回復  更多評論   

          # re: 關于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.  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 乐亭县| 肃北| 克什克腾旗| 固阳县| 浑源县| 惠水县| 隆安县| 巨鹿县| 崇阳县| 合阳县| 阿拉善右旗| 建阳市| 资中县| 拉孜县| 盐池县| 黑河市| 鸡西市| 铁岭市| 前郭尔| 西吉县| 鹿泉市| 九寨沟县| 石门县| 蒙城县| 资讯 | 南宫市| 东阿县| 湘乡市| 松原市| 庆阳市| 旌德县| 中阳县| 龙山县| 阿鲁科尔沁旗| 贵南县| 怀宁县| 福贡县| 太谷县| 桂阳县| 阳江市| 井研县|