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
-
意義:
- 更好的封裝和隱藏,使外部類不能隨意存取修改,提高程式的安全性,保護資料
- 隱藏程式碼的實現細節
- 統一介面
- 增加系統的可維護性
6.2.2 繼承
-
繼承:指父類和子類之間共享的資料和方法
- 子類(subclass),父類或超類(superclass)
- 父類包括所有直接或間接被繼承的類
- 除此之外類和類之間還有依賴、組合、聚合等關係
- 子類(subclass),父類或超類(superclass)
-
Java 中類只有單繼承,沒有多繼承
- 介面可以多繼承
-
意義:
- 子類可以繼承父類的狀態和行為
- 可以修改父類的狀態或者過載父類的行為
- 可以新增新的狀態和行為
-
作用
- 更好進行抽象和分類
- 增強程式碼的複用率,提高開發效率和可維護性
-
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
-
注意點:
- super 呼叫父類方法,必須位於構造方法第一行
- super 只能出現在子類的方法或者構造方法中
- super 和 this 不能同時呼叫構造方法
-
與 this 對比
super this 代表物件 代表父類物件的應用 代表呼叫者這個物件 前提 只能在繼承條件下使用 沒有顯式繼承條件也可以使用 構造方法 父類的構造 本類的構造
-
-
方法重寫
- 是重寫方法,與屬性無關
- 在 JDK 1.5 後可以使用 @Override 標註表示進行了方法重寫
- 重寫後父類呼叫該方法,是實現的子類的方法,而不是父類的方法
- 重寫快捷鍵(IDEA):
Alt+Insert
- 要求:
- 需要有繼承關係,子類重寫父類的方法
- 方法名、引數列表必須相同,方法體不同
- 修飾符範圍:可以擴大,不能縮寫
- \(pubilc>protected>default>private\)
- 丟擲異常範圍:可以縮小,不能擴大
- \(ClassNotFoundException<Exception\)
- 用途:
- 父類的功能子類不一定需要或不一定滿足
6.2.3 多型
- 多型是指不同物件收到同一個訊息(呼叫方法)可產生不同的效果,其實現的細節則由物件自行決定
- 多型可實現動態編譯,增強可擴充套件性
- 實現要求:
- 父類與子類有繼承關係
- 方法需要重寫
- 有些方法不能重寫:static、final、private
- 父類引用指向子類物件
- 注意點:
- 多型是方法的多型,屬性沒有多型
- 父類與子類有關係
- 如果沒有關係會發生型別轉換異常:\(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;
- 可能會丟失一些本來的方法
-
存在意義:方便方法呼叫,減少重複程式碼,簡潔
-
-
型別轉換條件
- 父類引用指向子類物件
- 把子類轉換為父類,向上轉型,自動轉換
- 把父類轉化為子類,向下轉型,強制轉換
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{ …… }
-
介面可以多繼承,從而側面實現多繼承
-
-
要點:
- 約束
- 可以實現不相關類的相同行為,而,不需要考慮這些類之間的層次關係。一定意義上實現多繼承
- 介面不能被例項化,介面中沒有構造方法
- 可以實現多個介面
- 實現介面必須重寫全部方法
-
介面中的常量
-
介面中主要是抽象方法,但是也存在常量
-
格式:
type NAME = value;
type:可以為任意型別
NAME:為常量名,通常為大寫
value:為常量值
-
在介面定義的常量可以被實現該介面的多個類共享
- 與 C 中 #define 和 C++ 中的 const 定義的常量相同
-
介面中定義的常量具有 public、static、final 屬性,通常省略
-
-
在 java 8 中的介面
- 在Java 8 中新添加了 static 方法
- 具有實現體的方法(default 方法)
- 預設方法的用途:提供了一個預設實現。子類在 implements 可以不用重新寫實現方法