1. 程式人生 > 其它 >Java 語言-6 面向物件程式設計

Java 語言-6 面向物件程式設計

6.1 認識面向物件

  • 面向過程 & 面向物件
    • 面向過程的思想:步驟清晰簡單;合適處理一些較為簡單的問題
    • 面向物件的思想:以分類的思維模式處理問題;合適處理複雜的問題,適合處理多人協助問題
    • 對於描述複雜的事物,為了從巨集觀上把握,從整體上合理分析,我們需要使用面向物件的思路來分析整個系統。到了具體微觀操作,我們仍需要面向過程的思路去處理問題
  • 面向物件程式設計(Object Oriented Programming,OOP)
    • 本質:以類的方式組織程式碼,以物件的組織(封裝)資料
    • 程式設計思想:抽象
    • 三大特性:封裝、繼承、多型
  • 設計思想的要點
    • 認為客觀世界由各種物件組成
    • 程式的分析和設計都圍繞著:有哪些物件類;每個類有哪些屬性、方法;類之間的關係(繼承、關聯……);物件之間傳送訊息(呼叫方法)等進行
  • 理解:
    • 從認識論角度考慮是先有物件後有類
    • 從程式碼執行角度考慮是先有類後有物件

6.2 面向物件三大特徵

6.2.1 封裝

  • 封裝:是類物件的狀態和方法,就是將欄位和方法封裝在一個類中

  • 封裝:主要是模組化和資訊隱藏兩個方面

    • 模組化:將屬性和行為封裝在類中,程式定義多個類
    • 資訊隱蔽:將類的細節部分隱藏起來,使用者只通過保護的介面訪問某個類
  • 封裝可用於完成程式設計要追求的“高內聚,低耦合”

    • 高內聚:類的內部操作細節,不允許外部干涉
    • 低耦合:僅暴露少量方法給外部
  • 方法:使用 private 關鍵字對類或者成員進行封裝,再使用 setXXX() 和 getXXX() 方法對類的屬性進行存取,分別稱為 setter 和 getter

    • 示例:

      class Person{
          private int age;
          public void setAge(int age){
              if(age>0 && age<200)this.age = age;
          }
          pubilc int getAge(){
              return age;
          }
      }
      
    • 簡單記憶:屬性私有,get/set

  • 實現快速封裝快捷鍵(IDEA):Alt+Insert

  • 意義:

    1. 更好的封裝和隱藏,使外部類不能隨意存取修改,提高程式的安全性,保護資料
    2. 隱藏程式碼的實現細節
    3. 統一介面
    4. 增加系統的可維護性

6.2.2 繼承

  • 繼承:指父類和子類之間共享的資料和方法

    • 子類(subclass),父類或超類(superclass)
      • 父類包括所有直接或間接被繼承的類
    • 除此之外類和類之間還有依賴、組合、聚合等關係
  • Java 中類只有單繼承,沒有多繼承

    • 介面可以多繼承
  • 意義:

    • 子類可以繼承父類的狀態和行為
    • 可以修改父類的狀態或者過載父類的行為
    • 可以新增新的狀態和行為
  • 作用

    1. 更好進行抽象和分類
    2. 增強程式碼的複用率,提高開發效率和可維護性
  • Java 實現繼承是通過 extands 關鍵字,意思是“擴充套件”

    • 例如:

      public class Student extands Person{
          ……
      }
      
    • 如果沒有 extends 子句,則預設為繼承於 java.lang.Object

      • 所有的類都是直接或者間接繼承 Object 類
  • 繼承關係:相當於 is 關係

  • 欄位

    • 欄位的繼承:子類可以繼承父類的所有欄位
    • 欄位的隱藏:子類重新定義一個從父類那裡繼承來的變數完全相同的變數,稱為域的隱藏
      • 在實際應用中較少
    • 欄位的新增:在定義子類時,加上新的域變數
      • 在實際應用中較多
  • 方法

    • 方法的繼承:父類非私有方法也可以被子類自動繼承
    • 方法的覆蓋:也稱為方法重寫,子類也可以重新定義與父類同名的方法,實現對父類方法的覆蓋
    • 方法的新增:子類可以新加一些方法
      • 方法過載是特殊的方法的新增
  • 判斷兩個物件之間的關係使用 instanceof 關鍵字

    • 如果有繼承關係返回 True,否則返回 False

    • 示例:

      object instanceof Student
      
  • 檢視繼承關係快捷鍵(IDEA):ctrl+H

  • 在子類訪問父類屬性和方法使用 super 關鍵字

    • 例如:呼叫父類 name 屬性

      super.name
      
    • 注意點:

      1. super 呼叫父類方法,必須位於構造方法第一行
      2. super 只能出現在子類的方法或者構造方法中
      3. super 和 this 不能同時呼叫構造方法
    • 與 this 對比

      super this
      代表物件 代表父類物件的應用 代表呼叫者這個物件
      前提 只能在繼承條件下使用 沒有顯式繼承條件也可以使用
      構造方法 父類的構造 本類的構造
  • 方法重寫

    • 是重寫方法,與屬性無關
    • 在 JDK 1.5 後可以使用 @Override 標註表示進行了方法重寫
    • 重寫後父類呼叫該方法,是實現的子類的方法,而不是父類的方法
    • 重寫快捷鍵(IDEA):Alt+Insert
    • 要求:
      1. 需要有繼承關係,子類重寫父類的方法
      2. 方法名、引數列表必須相同,方法體不同
      3. 修飾符範圍:可以擴大,不能縮寫
        • \(pubilc>protected>default>private\)
      4. 丟擲異常範圍:可以縮小,不能擴大
        • \(ClassNotFoundException<Exception\)
    • 用途:
      • 父類的功能子類不一定需要或不一定滿足

6.2.3 多型

  • 多型是指不同物件收到同一個訊息(呼叫方法)可產生不同的效果,其實現的細節則由物件自行決定
  • 多型可實現動態編譯,增強可擴充套件性
  • 實現要求:
    1. 父類與子類有繼承關係
    2. 方法需要重寫
      • 有些方法不能重寫:static、final、private
    3. 父類引用指向子類物件
  • 注意點:
    1. 多型是方法的多型,屬性沒有多型
    2. 父類與子類有關係
      • 如果沒有關係會發生型別轉換異常:\(ClassCastException\)

6.3 super 的使用

  • 使用 super 訪問父類的變數和方法

    • 也可以使用 this 來訪問父類的域和方法

    • 例如:假設有一個類的父類有 age() 方法 ,在該類中使用 age()

      void testThisSuper(){
          int a;
          a = age;
          a = this.age;
          a = super,age;
      }
      

      這三種訪問結果均相同

    • 為什麼有了 this 還需要使用 super

      • 有些時候為了明確地指明父類的變數和方法
      • 訪問被子類所隱藏的同名變數
      • 當覆蓋父類方法的同時,又需要呼叫父類的方法
  • 使用父類的構造方法

    • 構造方法與類名相同,是不能繼承的

      • 不能說父類(例如:Person)有一個構造方法(Person())子類(例如:Student)也自動有一個構造方法(Student())
    • 但是可以通過 super 來呼叫父類的構造方法

    • 例如:父類 Person 的構造方法 Person(String name, int age),子類呼叫

      public Student(String name, int age,String school) {
              super(name,age);
              this.shool = school;
          }
      }
      

      使用時,super() 語句必須放在第一句

6.4 型別轉化

  • 這裡是指父類物件與子類物件的轉化,與基本資料型別的轉換類似

    • 子類物件可以被視為其父類的一個物件

      • 例如:一個 Student 物件可以被視為一個 Person 的物件
    • 父類物件不能視為子類物件

  • “低”轉“高”自動轉換:如果一個方法的形式引數定義的是 父類物件,那麼呼叫這個方法時,可以使用子類物件作為實際引數

    • “低”指父類級別,“高”指子類級別

    • 例如:Person 是 Student 的父類

      Person student = new Student();
      
  • “高”轉“低”強制轉換:如果父類物件引用指向的實際是一個子類物件,那麼這個父類物件的引用可以使用強制型別轉換成為子類的引用

    • 轉換方法與基本型別型別轉換類似:在物件前新增()

    • 例如:

      Person student = new Student();
      Stuednt obj = (Student) sutdent;
      
      • 可能會丟失一些本來的方法
    • 存在意義:方便方法呼叫,減少重複程式碼,簡潔

  • 型別轉換條件

    1. 父類引用指向子類物件
    2. 把子類轉換為父類,向上轉型,自動轉換
    3. 把父類轉化為子類,向下轉型,強制轉換

6.5 介面

  • 介面就是規範,定義的是一組規則;

    • 本質就是契約;OO 的精髓,是對物件的抽象最能體現的一點
    • 也是一種引用型別
  • 介面 & 普通類 & 抽象類

    • 普通類:只有具體實現
    • 抽象類:具體實現和規範(抽象方法)都有
    • 介面:只有規範
  • 宣告介面使用 interface 關鍵字,宣告之後的方法都自動是 public abstract

    • 定義的時候 public、abstract 兩個關鍵字是可以省略的

    • 宣告類的關鍵字是 class

    • 例如:介面的簡單操作

      public interface UserService{
          void add(String name);
          void delete(String name);
          void update(String name);
          void query(String name);
      }
      

      在介面中很多東西是看不見的,所以可以直接用返回值型別、方法名以及引數列表即可定義

  • 使用 implements 實現介面。實現介面,就必須要實現介面全部的方法

    • 實現類一般命名以 Impl 結尾

    • 例如:實現介面 UserService

      pubilc class UserServiceLmpl implements UserService{
          ……
      }
      
    • 介面可以多繼承,從而側面實現多繼承

  • 要點:

    1. 約束
    2. 可以實現不相關類的相同行為,而,不需要考慮這些類之間的層次關係。一定意義上實現多繼承
    3. 介面不能被例項化,介面中沒有構造方法
    4. 可以實現多個介面
    5. 實現介面必須重寫全部方法
  • 介面中的常量

    • 介面中主要是抽象方法,但是也存在常量

    • 格式:

      type NAME = value;
      

      type:可以為任意型別

      NAME:為常量名,通常為大寫

      value:為常量值

    • 在介面定義的常量可以被實現該介面的多個類共享

      • 與 C 中 #define 和 C++ 中的 const 定義的常量相同
    • 介面中定義的常量具有 public、static、final 屬性,通常省略

  • 在 java 8 中的介面

    • 在Java 8 中新添加了 static 方法
    • 具有實現體的方法(default 方法)
      • 預設方法的用途:提供了一個預設實現。子類在 implements 可以不用重新寫實現方法