<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-199  評論-203  文章-11  trackbacks-0
    有時候,我們可能想要構造一個很抽象的父類對象,它可能僅僅代表一個分類或抽象概念,它的實例沒有任何意義,因此不希望它能被實例化。例如:有一個父類“ 水果(Fruit)”,它有幾個子類“蘋果(Apple)”、“橘子(Orange)”、“香蕉(Banana)”等。水果在這里僅僅只是作為一個分類,顯然水果的實例沒有什么意義(就好像一個人如果告訴你他買了一些水果但是卻不告訴你是蘋果還是橘子,你很難想象他到底買的是什么。)。而水果類又要能被子類化,這就要求我們使用抽象類(abstract class)來解決這個問題。
    在java中,通過在class關鍵字前增加abstract修飾符,就可以將一個類定義成抽象類。抽象類不能被實例化。例如:
              定義抽象類水果(Fruit)
              public abstract class Fruit {
                      ……
              }
               如果我們試圖用以下語句來獲得一個實例,將無法編譯成功。
               Fruit fruit = new Fruit();
    而我們仍然可以構造水果類的子類,如:
              子類“蘋果(Apple)”
               public class Apple extends Fruit {
                       ……
               }
              子類“橘子(Orange)”
               public class Orange extends Fruit {
                       ……
               }
    這樣就達到我們的目的了。
    抽象類除了能象普通類一樣可以擁有一般的屬性和方法,也可以擁有抽象方法(abstract method)。例如:
               抽象類“形狀(Shape)”擁有抽象方法draw()。
               public abstract class Shape {
                      ……
                      public abstract void draw();
                      ……
               }
    抽象方法與抽象的行為相對應,通常是這個行為對父對象沒有意義,而子對象有具體動作。例如方法draw()對于類Shape沒有意義,而類Shape的子類矩形(Rectangle)的方法draw()可以有實際的動作(根據矩形的四個頂點畫出矩形的四個邊),子類圓(Circle)的方法draw()也可以有實際的動作(根據圓心和半徑畫出圓周)。
    抽象類可以有抽象方法也可以沒有抽象方法;但是如果一個類有抽象方法,那這個類只能定義為抽象類。
               如果按照以下代碼類“形狀(Shape)”仍然擁有抽象方法draw(),但沒有定義為抽象類,將會編譯失敗。
               public class Shape {
                      ……
                      public abstract void draw();
                      ……
               }
    抽象方法還有一個特點是,它強迫子類要么仍然保持抽象性(即不具體實現該方法并仍然定義為抽象類),要么具體表現出這個方法的行為(實現具體的動作或者通過拋出UnsupportedOperationException異常來表明不支持該行為)。這樣也可以強化多態性。
    上面簡要分析了抽象類,下面談談接口(interface)。java語言使用關鍵字interface定義一個接口。接口也是抽象對象,它甚至比抽象類更抽象。接口中的方法都是抽象方法。
    一個接口可以繼承其他接口;一個類通過關鍵字implements聲明要實現一個接口,并具體實現接口的方法。
               例如:有一個接口InterfaceA,

    Java代碼 
    public   interface  InterfaceA {    
             void  methodA();    
    }   
      
               類ClassA實現接口InterfaceA。

    Java代碼 
    public   class  ClassA implements InterfaceA {    
              public   void  methodA() {    
                   System.out.println( "methodA of ClassA implements InterfaceA" );    
             }    
    }   
      
    如果是抽象類實現一個接口,那么抽象類中可以不具體實現接口的方法(保持其抽象性),而由其子類去實現。
               抽象類ClassB實現接口InterfaceA,但是沒有具體實現方法methodA(),

    Java代碼 
    public   abstract   class  ClassB  {           }   
      
               子類ClassBSub實現接口InterfaceA,但是沒有具體實現方法methodA(),

    Java代碼 
    public   class  ClassBSub {    
             public   void  methodA() {    
                  System.out.println( "methodA of ClassBSub the subclass of ClassB" );    
            }    
    }   
      
    接口和抽象類顯著的共同點是接口和抽象類都可以有抽象方法。
    接口和抽象類的不同點有:
               (1)抽象類可以有實例變量,而接口不能擁有實例變量,接口中的變量都是靜態(static)的常量(final)。
               (2)抽象類可以有非抽象方法,而接口只能有抽象方法。
    java中,類與類之間是不能多繼承的。java之所以禁止類與類之間的多繼承是因為多繼承有很大的缺點。
    多繼承雖然能使子類同時擁有多個父類的特征,但是其缺點也是很顯著的,主要有兩方面:
    (1)如果在一個子類繼承的多個父類中擁有相同名字的實例變量,子類在引用該變量時將產生歧義,無法判斷應該使用哪個父類的變量。例如:
               類ClassA:

    Java代碼 
    public   class  ClassA {    
            protected   int  varSame =  0 ;    
    }   
      
               類ClassB:

    Java代碼 
    public   class  ClassB {    
             protected   int  varSame =  1 ;    
    }   
      
               子類ClassC:(假設允許類與類之間多繼承)

    Java代碼 
    public   class  ClassC  extends  ClassA, ClassB {    
             public   void  printOut() {    
                    System.out.println( super .varSame);    
            }    
             public   static   void  main(String[] args) {    
                    ClassC classC =  new  ClassC();    
                    classC.printOut();    
            }    
    }   
      

               上面程序的運行結果會是什么呢?輸出0還是1?
    (2)如果在一個子類繼承的多個父類中擁有相同方法,子類中有沒有覆蓋該方法,那么調用該方法時將產生歧義,無法判斷應該調用哪個父類的方法。例如:
               類ClassA:

    Java代碼 
    public   class  ClassA {    
             public   void  printOut() {    
                    System.out.println( 0 );    
            }    
    }   
     

               類ClassB:

     

    Java代碼 
    public   class  ClassB {    
             public   void  printOut() {    
                    System.out.println( 1 );    
            }    
    }   
      
               子類ClassC:(假設允許類與類之間多繼承)

    Java代碼 
    public   class  ClassC  extends  ClassA, ClassB {    
                        public   static   void  main(String[] args) {    
                               ClassA classA =  new  ClassC();    
                               classA.printOut();       // -------------------------  A行    
                               ClassB classB =  new  ClassC();    
                               classB.printOut();       // -------------------------  B行    
                               ClassC classC =  new  ClassC();    
                               classC.printOut();        //-------------------------  C行    
                       }    
               }   
      
               上面程序的運行結果會是什么呢?A、B、C三行的輸出是0還是1?
    正因為有以上的致命缺點,所以java中禁止一個類繼承多個父類;但是幸運的是java提供了接口,并能通過接口的功能獲得多繼承的許多優點而又摒棄了類與類多繼承的缺點。
    java允許一個接口繼承多個父接口,也允許一個類實現多個接口,而這樣的多繼承有上面提到的缺點馬?
    答案是沒有,這是由接口的抽象性決定的。
    正如前面介紹的,在接口中不能有實例變量,只能有靜態的常量,不能有具體的方法(包含方法體),只能有抽象方法,因此也就摒棄了多繼承的缺點。
    對于一個類實現多個接口的情況,因為接口只有抽象方法,具體方法只能由實現接口的類實現,在調用的時候始終只會調用實現類的方法(不存在歧義),因此不存在多繼承的第二個缺點;而又因為接口只有靜態的常量,但是由于靜態變量是在編譯期決定調用關系的,即使存在一定的沖突也會在編譯時提示出錯;而引用靜態變量一般直接使用類名或接口名,從而避免產生歧義,因此也不存在多繼承的第一個缺點。
    對于一個接口繼承多個父接口的情況也一樣不存在這些缺點。
    請看以下示例。
                接口A:

    Java代碼 
    public   interface  InterfaceA {    
             int  len =  1 ;    
             void  output();    
    }   
      
                接口B:

    Java代碼 
    public   interface  InterfaceB {    
               int  len =  2 ;    
               void  output();    
    }   
      
                接口Sub繼承接口A和接口B:

    Java代碼 
    public   interface  InterfaceSub  extends  InterfaceA, interfaceB {            }   
      
                類Xyz實現接口Sub:

    Java代碼 
    public   class  Xyz  implements  InterfaceSub {    
             public   void  output() {    
                    System.out.println( "output in class Xyz." );    
            }    
              public   void  outputLen( int  type) {    
                      switch (type) {    
                              case  InterfaceA.len:    
                                     System.out.println( "len of InterfaceA=." +type);    
                                      break ;    
                              case  InterfaceB.len:    
                                     System.out.println( "len of InterfaceB=." +type);    
                                      break ;    
                     }    
            }    
            public   static   void  main(String[] args) {    
                   Xyz xyz=  new  Xyz ();    
                   xyz .output();    
                   xyz .outputLen();    
           }    
      

               以上代碼不存在什么問題,但是如果試圖編寫以下存在沖突的代碼,則會編譯失敗。

    Java代碼 
    Xyz xyz =  new  Xyz();    
    int  len = xyz.len;    
    System.out.println(len);   
      

    由于引入了接口,java顯得非常靈活,也使得java中的多態性更加富有魔力。
    posted on 2009-04-10 08:18 Werther 閱讀(1894) 評論(3)  編輯  收藏 所屬分類: 10.Java

    評論:
    # re: Java抽象類和接口和繼承之間關系 [未登錄] 2009-04-10 14:23 | lip
    很好狠好,講的不錯~~  回復  更多評論
      
    # re: Java抽象類和接口和繼承之間關系 [未登錄] 2009-04-10 23:59 | stanleyxu2005
    去關心一下d語言的mixin吧。這個是一個新的解決方案。  回復  更多評論
      
    # re: Java抽象類和接口和繼承之間關系 2009-04-13 12:30 | Java蜘蛛人 --鄭成橋
    說實話寫的還可以,適合新人,但是對于老鳥,視乎沒有寫全面,接口的好處是什么? 為什么使用接口? 這些加上去。 Java 與模式里 寫了的  回復  更多評論
      
    主站蜘蛛池模板: 狠狠久久永久免费观看| 最近2018中文字幕免费视频| 最近免费中文字幕4| 亚洲欧洲自拍拍偷午夜色| 在线看无码的免费网站| 自怕偷自怕亚洲精品| 久久久久久影院久久久久免费精品国产小说 | 亚洲成人午夜电影| 中文字幕在线观看免费视频 | 亚洲成AV人片天堂网无码| 国产一级黄片儿免费看| 亚洲国产婷婷六月丁香| 久久久久久成人毛片免费看| 亚洲激情校园春色| 免费看AV毛片一区二区三区| 在线播放国产不卡免费视频| 区久久AAA片69亚洲| 97免费人妻在线视频| 亚洲午夜精品久久久久久app| 四虎成人精品在永久免费| 国产99视频精品免费视频76| 亚洲AV综合色区无码另类小说| 97免费人妻在线视频| 亚洲欧美日韩中文字幕在线一区| 高清在线亚洲精品国产二区| 中文字幕免费播放| 亚洲精品视频免费看| 国产精品视频免费一区二区三区| 一级毛片在播放免费| 久久久久亚洲精品美女| 欧美a级成人网站免费| 美女视频黄频a免费观看| 亚洲AV永久无码精品一百度影院 | 亚洲免费视频网址| 国产AV无码专区亚洲AV麻豆丫 | 国产成人精品免费视频软件| 中文字幕av免费专区| 国产亚洲精品影视在线| 亚洲综合国产精品第一页| 亚洲一级毛片免费在线观看| 国产精品亚洲一区二区三区在线观看|