2017 - 10 -16 面向對象 多態 抽象類 接口 形參和返回值 鏈式編程 包 訪問修飾符 內部類

1 多態
(1)同一個對象(事物),在不同時刻體現出來的不同狀態
  舉例:
     貓是貓,貓是動物。
     水(液態,固態,氣態)。
(2)多態的前提:
       A:要有繼承關係。
       B:要有方法重寫。
             其實沒有也是可以的,但是如果沒有這個就沒有意義。
             動物 d = new 貓();
             d.show();
             動物 d = new 狗();
             d.show();
       C:要有父類引用指向子類對象那個。

               父 f = new 子類;

(3)多態中的成員訪問特點:
       A:成員變量
           編譯看左邊,運行看左邊
       B:構造方法
           創建子類對象的時候,訪問父類的構造方法,對父類的數據進行初始化
       C:成員方法
           編譯看左邊,運行看右邊(成員方法存在重寫)
       D:靜態方法
           編譯看左邊,運行看左邊
           (靜態和類相關,算不上重寫,所以訪問還是左邊的)
         
       由於成員方法存在方法重寫,所以它看右邊

class Fu{
      public int num =100;
      public void show(){
        System.out.println("show Fu");
}
      public static void function(){
        System.out.println("function Fu");
           }
}
class Zi extend Fu{
       public int num =1000;
       public int num2 =2000;
       public void show(){
        System.out.println("show Zi");
}
       public static void function(){
        System.out.println("function Zi");
}
}
class DuoTaiDemo{
      public static void main(String[] args){
        Fu f = new Zi();
        System.out.println(f.num);
        //報錯 父類中找不到num2
        //System.out.println(f.num2);
        f.show();
        f.function();
}
}               
     輸出結果:100 show Zi function Fu

(4) 多態的好處
    A:提高了代碼的維護性(繼承保證)
    B:提高了代碼的擴展性(調用時,直接調用父類名,而不用直接調用子類名)
   例如:
    Dog a = new Dog();
    Cat b = new Cat();
    Pig c = new Pig();
    AnimalTool.useDog(a);
    AnimalTool.useCat(b);
    AnimalTool.usePig(c);
----------------------------------------
    Dog a = new Dog();
    Cat b = new Cat();
    Pig c = new Pig();
    AnimalTool.useAnimal(a);
    AnimalTool.useAnimal(b);
    AnimalTool.useAnimal(c);

(5) 多態的弊端
    不能使用子類的特有功能,只能使用父類中定義了的功能。

    那如何使用子類的特有功能?
      A:創建子類對象調用特有功能。(可以,但是很多時候不合理,而且太佔內存了)
      Fu f = new Zi();
      f.show();
      //f.method(); 無法調用子類的method
      //所以創建另一個子類對象
      Zi z = new Zi();
      z.show();
      z.method();

      B:把父類的引用強制轉換爲子類的引用。(向下轉型)
      Zi z = (Zi)f;
      z.show();
      z.method();
 -----------------------------------------
      對象間的轉型問題:
        向上轉型:
          Fu f = new Zi();
        向下轉型:
          Zi z = (Zi)f; //要求該f必須是能夠轉換爲Zi的。
(6) 繼承的時候:
       子類中有和父類一樣的方法,叫做重寫。
       子類中沒有父親中出現過的方法,方法就被繼承過來了

2 抽象類
(1)抽象類的概述:
      動物不應該定義爲具體的東西,而且動物中的吃,睡等也不應該是具體的。
      我們把一個不是具體的功能成爲抽象的功能,而一個類中如果有抽象的功能,該類必須是抽象類。
   
(2)抽象類的特點:
     A:抽象類和抽象方法必須用abstract關鍵字修飾
     B:抽象類中不一定有抽象方法,但是有抽象方法的類必須定義爲抽象類
     C:抽象類不能實例化
          因爲它不是具體的
          抽象類有構造方法,但是不能實例化?構造方法的作用是什麼呢?
          用於子類訪問父類數據的初始化
     D:抽象的子類
          a:如果不想重寫抽象方法,該子類是抽象類
          b:重寫所有的抽象方法,這個時候子類是一個具體的類

   **抽象類的實例化其實是靠具體的子類實現的,是多態的方式。
     Animal a = new Dog();

     a.eat();

abstract class Animal{
        //抽象方法
        //public abstract void eat(){} //空方法體,這個會報錯,抽象方法不能有主體
        public abstract void eat();
}
  
(3)抽象類的成員特點:
      成員變量:既可以是變量,也可以是常量。
      構造方法: 有。
                用於子類訪問父類數據的初始化。
      成員方法:既可以是抽象的,也可以是非抽象的。
      
      抽象類的成員方法特性:
       A:抽象方法,強制要求子類做的事情
       B:非抽象方法 子類繼承的事情,提高代碼複用性。

(4)抽象類的幾個小問題
    A:一個類如果沒有抽象方法,可不可以定義爲抽象類?如果可以,有什麼意義
    a:可以
    b:不讓創建對象

    B:abstract不能和哪些關鍵字共存
         private 衝突  (不能被繼承,但抽象要求重寫)
         final   衝突  (不能被重寫,但抽象要求重寫)
         static  無意義 (抽象無方法體,static可以直接訪問方法體)

3 接口
  爲了體現事物功能的擴展性,java中就提供了接口來定義這些額外功能,並不給出具體實現。
(1) 接口的特點:
        A:接口用關鍵字interface表示
           interface 接口名{}
        B:類實現接口用implements表示
           class 類名 implements 接口名{}
        C:接口不能實例化
             那麼,接口如何實例化呢?
              按照多態的方式來實例化
        D:接口的子類
           a:可以是抽象類,但意義不大
           b:可以是具體類,要重寫接口中的所有抽象方法(推薦方案)

    由此可見:
        A:具體類多態(幾乎沒有)
        B:抽象類多態(常用)
        C:接口多態(最常用)

//定義動物培訓接口
interface AnimalTrain{
     public abstract void jump();
}       

(2)接口成員特點
       成員變量:只能是常量
                 默認修飾符 public static final
       構造方法:沒有,因爲接口主要是擴展功能的,而沒有具體存在
       成員方法:只能是抽象方法
                 默認修飾符public abstract

(3) 類與類:
         繼承關係:只能單繼承,可以多層繼承。
    類與接口:
         實現關係,可以單實現,也可以多實現。
         並且還可以在繼承一個類的時候同時實現多個接口。
    接口與接口:
         繼承關係:可以單繼承,也可以多繼承

4 抽象類與接口的區別
   A:成員區別
    抽象類:
         成員變量:可以變量,也可以常量
         構造方法:有
         成員方法:可以抽象,也可以非抽象
    接口:
         成員變量:只可以是常量
         構造方法:無
         成員方法:只可以是抽象
   B:關係區別
    類與類:
         繼承關係:只能單繼承,可以多層繼承。
    類與接口:
         實現關係,可以但實現,也可以多實現。
         並且還可以在繼承一個類的時候同時實現多個接口。
    接口與接口:
         繼承關係:可以單繼承,也可以多繼承
 **C:設計理念區別
    抽象類 被繼承體現的是:"is a"的關係,抽象類中定義的是該繼承體系的共性功能。
    接口 被實現體現的是:"like a"的關係,接口中定義的是該繼承體系的擴展功能。

5 形式參數和返回值問題
     形式參數: 
         基本類型: 8種基本類型
         引用類型: 
           類:(匿名對象的時候已經用過)需要的是該類的對象
           抽象類:需要的是該抽象類的子類的對象
           接口:跟抽象類同理
     返回值類型: 
         基本類型: 8種基本類型
         引用類型: 
           類:返回的是該類的對象
           抽象類:返回的是該抽象類的子類的對象
           接口:返回的是該接口的實現類的對象

6 鏈式編程
    每次調用完畢方法後,返回的是一個對象。
  class StudentDemo{
     public Student getStudent(){
           return new Student();         
          }
}
     sd.getStudent().study();//鏈式編程

7 包
   A:其實就是文件夾
   B:作用
      a:把相同的類名放到不同的包中
      b:對類進行分類管理
  
   舉例:
      學生:增加,刪除,修改,查詢
      老師:增加,刪除,修改,查詢
      。。。
   方案1:按照功能分
        cn.itcast.add
              AddStudent
              AddTeacher
        cn.itcast.delete
              DeleteStudent
              DeleteTeacher
        cn.itcast.update
              UpdateStudent
              UpdateTeacher
    方案2:按照模塊分
        cn.itcast.teacher
              AddTeacher 
              DeleteTeacher
              UpdateTeacher
        cn.itcast.student
              AddStudent
              DeleteStudent
              UpdateStudent

    包的定義
          package 包名;
              多級包用.分開即可
    注意事項:
      A:package語句必須是程序的第一條可執行的代碼
      B:package語句在一個java文件中只能有一個
      C:如果沒有package,默認表示無包名

8 不同包下類之間的訪問
   
     第一個問題:找不到Demo       需要用包名.Demo
     第二個問題:程序包不存在     需要建立工程包
     第三個問題:Demo在包中不是公共的,無法訪問    設置訪問權限。

    導包:
      格式:import 包名;
      這種方式導入時到類的名稱
 
   **面試題:
      package,import,class有沒有順序關係?
       有
      package>import>class
      package:只能有一個
      import:可以有多個
      class:可以有多個,以後建議是一個

9 訪問修飾符
                                            public    protected     默認    private
 同一類中                               √                √              √            √
 同一包子類,其他類             √                √              √
 不同包子類                           √                √         
 不同包其他類                       √ 

10 內部類

(1)內部類概述:把類定義在其他類的內部,這個類就被稱爲內部類。
       舉例:在類A中定義了一個類B,類B就是內部類。
(2)內部類的訪問特點:
        A:內部類可以直接訪問外部類的成員,包括私有。
        B:外部類要訪問內部類的成員,必須創建對象。  
(3)內部類位置:
        成員位置:在成員位置定義的類,被稱爲成員內部類。
        局部位置:在局部位置定義的類,被稱爲局部內部類。(例如方法中)
(4)成員內部類:
    如何直接訪問內部類的成員?
      外部類名.內部類名  對象名 = 外部類對象.內部類對象;
       Outer.Inner oi = new Outer().new Inner();
            oi.show();
(5)成員內部類的修飾符:
     **private:爲了保證數據的安全性
     **static:爲了方便訪問數據
          注意:靜態內部類訪問的外部類數據必須用靜態修飾

        案例:我有一個人(人有身體,身體內有心臟) 
              不能直接讓外部訪問,必須要保證安全性。
          class Body{
               private class Heart{
                    public void operator(){
                        System.out.println("心臟搭橋");
               } 
      }
              public void method(){
                 if(如果你是外科醫生){
                     Heart h = new Heart();
                     h.operator();
                  }
          }
}
(6) 用static修飾後的內部類訪問
         class Outer{
              private int num = 10;
              private static int num2 = 100;
             //內部類用靜態修飾是因爲內部類可以看出是外部類的成員
              public static class Inner{
                     public void show(){
                           System.out.println(num);
              }
                     public static void show2(){
                           System.out.println(num);
              }
      }
}
         //格式:外部類名.內部類名 對象名 = new 外部類名.內部類名();
          Outer.Inner oi = new Outer.Inner();
            oi.show();
            oi.show2(); 
                       
         //show2()的另一種調用方式

            Outer.Inner.show2();

靜態內部類的作用:

https://www.zhihu.com/question/28197253
***11 成員內部類的面試題
       要求請填空,分別輸出30,20,10
   class Outer{
         public int num = 10;
         class Inner{
            public int num = 20;
            public void show(){
                    int num = 30;
                    System.out.println(?);   // num
                    System.out.println(??);  // this.num
                    System.out.println(???); // Outer.this.num /new Outer().num
                }
        }
}     

12 局部內部類
      A:可以直接訪問外部類的成員
      B:在局部位置,可以創建內部類對象,通過對象調用內部類方法,來使用局部內部類功能

    ***面試題:
         局部內部類訪問局部變量的注意事項?
         A:局部內部類訪問局部變量必須使用final修飾
         B:爲什麼?
            局部變量是隨着方法的調用而調用,隨着調用完畢而消失。
            而堆內存的內容並不會立即消失,所以,我們加finaal修飾。
            加入final修飾後,這個變量就變成了常量,既然是常量,你消失了,我在內存中存儲的數據是20,所以,我還是有數據在使用。
    (反編譯之後,就是一個常量)
     class Outer{
             private int num = 10;
             public void method(){
                   final int num2 = 20;
                   class Inner{
                       public void show(){
                         System.out.println(num);
                         // 從內部類中訪問本地變量num2,需要被聲明爲最終類型
                         System.out.println(num2);
                   }
              }
            Inner i = new Inner();
            i.show();
      }
}
發佈了31 篇原創文章 · 獲贊 2 · 訪問量 9204
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章