java學習-多型、抽象類、介面
一、多型
1.1多型的概述
- 多型是面向物件一大特徵
- 多型 : 表示事物的多種形態(事物的多種表現形式)
- 多型發生的前提:
1)需要具有子父類的繼承關係(類與介面實現關係)
2)子類重寫從父類繼承來的方法
3)父類的引用指向子類的物件
舉例 :
class Person{}
class Doctor extends Person{}
class Teacher extends Person{}
多型表示式:
Person p; // 父類引用
new Doctor(); // 子類物件
new Teacher() ;// 子類物件
Person p = new Doctor(); // 人類p的表現形式是醫生
Person p1 = new Teacher(); // 人類p1的表現形式是教師
以上表達式能體現出人類的多種表現形式,這就是多型的概念
程式碼
public class Person { public void eat() { System.out.println("人都需要吃飯"); } }
public class Doctor extends Person { @Override public void eat() { System.out.println("醫生吃的比較清淡"); } }
publicclass Teacher extends Person { @Override public void eat() { System.out.println("教師今天想吃涼皮"); } }
public class TestDuoTai { public static void main(String[] args) { // 多型表示式 Person p = new Doctor(); p.eat();// 醫生吃的比較清淡 Person p1 = new Teacher(); p1.eat();// 教師今天想吃涼皮 } }
1.12多型中成員方法的特點
- 編譯看左,執行看右
使用多型表示式呼叫成員方法
1)編譯看左 : 編譯程式碼時, 如果多型表示式呼叫的這個方法, 在 等號的左邊的型別中不存在(沒定義), 那麼直接報錯,無法編譯通過. 如果等號左邊的型別中存在呼叫的方法,編譯成功
2)執行看右 : 使用多型的表示式呼叫方法,執行時動態繫結等號右邊的型別中的方法實現, 實際執行的就是等號右邊子類中的重寫方法
程式碼
public class Person { public void eat() { System.out.println("人都需要吃飯"); } }
public class Doctor extends Person { @Override public void eat() { System.out.println("醫生吃的比較清淡"); } // 醫生特有的救人功能 public void savePerson() { System.out.println("醫生可以治病救人"); } }
public class Teacher extends Person { @Override public void eat() { System.out.println("教師今天想吃涼皮"); } // 老師特有功能授課 public void teach() { System.out.println("老師可以授課"); } }
public class TestDuoTai { public static void main(String[] args) { // 多型表示式 // 1. 編譯看左,執行看右 Person p = new Doctor(); // eat方法在等號左邊的型別Person中存在(定義) p.eat();//醫生吃的比較清淡 // savePerson方法在等號左邊的型別Person中不存在,因此報出編譯錯誤 // p.savePerson(); //The method savePerson() is undefined for the type Person Person p1 = new Teacher(); p1.eat();//教師今天想吃涼皮 // p1.teach(); } }
1.3多型的向上和向下轉型
- 多型向上轉型 : 父類的引用指向子類物件(多型表示式)
Person p = new Doctor();
向上轉型的實質 : 物件引用p使用範圍縮小, 只能使用子父類中的共有方法
2.多型向下轉型 :
目的 : 為了解決多型表示式中,無法使用子類特有方法的侷限性, 想要使用子類中的特有方法功能
多型向下轉型公式: 將指向子類物件的父類引用, 恢復成子類型別
舉例 : Doctor d = (Doctor)p;
向下轉型實質 : 物件引用p使用範圍變大, 可以使用子類中的內容
1.4多型的好處
- 多型好處 : 提高程式碼的擴充套件性
- 方法的引數列表上 : 定義一個方法功能, 形式引數可以是父類資料型別, 在方法中可以使用父類引數中的任意功能; 當呼叫這個方法時, 實際引數可以是當前父類型別物件本身,也可以是這個父類的任意一個子類型別物件
- 一個型別不一定非通過new物件才能建立, 很多情況下, 方法功能返回值型別就是引用資料型別, 需要一個對應的引用型別接方法返回值, 若這個引用的具體型別不清楚,可以直接使用一個父類型別作為這個方法的返回值型別承接
需求 : 現有一農場,需要設計出一個方法, 功能是提供不同的動物型別,能輸出每一種動物需要投喂的食物, 請根據多型設計出這個方法功能
舉例 : 給該方法傳遞貓型別資料 : 提示, 餵魚 ; 給該方法傳遞狗型別資料 : 提示 , 吃骨頭; 給該方法傳遞羊型別資料 : 提示 , 喂草 .... 每一種動物都能得到對應的餵食結果
程式碼
public class Animal { // 將所有動物都需要餵食功能 : eat public void eat() { System.out.println("所有動物都需要餵食"); } }
public class Cat extends Animal { @Override public void eat() { System.out.println("貓餵魚"); } }
public class Dog extends Animal { @Override public void eat() { System.out.println("狗喂骨頭"); } }
public class Farmer { // 方法功能 : 將每一種動物餵食結果顯示出來 public void wei(Animal a) {// Animal a = new Sheep(); a.eat(); } public void useI(int i) {// int i = 10; System.out.println(i); } }
二、抽象類
2.1抽象方法和抽象類
- 抽象 : 表示無法使用語言進行描述, 無法實現的, 虛無縹緲,沒有具體存在
將事物的共性向上抽取,抽取到父類中, 但是當共性抽取到一定程度時, 父類中不知道如何實現共性內容才能讓每一個子類都滿足實際需求, 於是父類中將共性方法只做方法的宣告,而沒有方法的實現,這樣的方法稱為抽象方法
2.抽象方法的定義:
需要使用關鍵字 : abstract
修飾符 abstract 返回值型別 方法名(引數列表);
3.抽象類的定義:
修飾符 abstract class 類名{
// 抽象方法只能存在於抽象類中
}
4.抽象方法存在是為了為子類限定一些需要實現的規則
程式碼
public abstract class Animal { // 抽象方法 // The abstract method eat in type Animal can only be defined by an abstract class // 抽象方法只能定義在抽象類中 public abstract void eat(); }
2.2抽象的特點
- 抽象類和抽象方法都需要使用 abstract 抽象關鍵字
public abstract class Animal{
public abstract void eat();
}
2.抽象類和抽象方法之間的關係:
1)抽象方法必須定義在抽象類中
2)抽象類中可以沒有抽象方法
3.抽象類的例項化(例項化 : new物件)
1)抽象類不能例項化物件(不能new物件)
因為抽象類中可以含有抽象方法, 而抽象方法因為沒有方法體,不能執行的,因此抽象類不能new物件
2)抽象類等著當父類,等著被子類繼承, 需要一個子類繼承這個抽象類, 讓子類將抽象父類中的所有抽象方法全部重寫, 通過建立子類物件,實現方法的呼叫
4.抽象類的子類前途:
1)子類將抽象父類中的所有抽象方法全部重寫, 子類可以正常建立物件使用
2)子類沒有將抽象父類中的所有抽象方法全部重寫, 子類仍然還是一個抽象類
2.3抽象類中的成員
抽象類中的成員 : 先把抽象類當做一個普通類, 在此基礎上可以定義抽象方法
1.可以定義成員變數
2.可以定義構造方法
一個型別是否可以定義構造方法,與這個型別能否建立物件無關, 與型別中是否能定義成員變數有關. 只要一個型別中可以定義成員變數,那麼這個型別就可以定義構造方法
3.可以定義非抽象方法
為了給子類直接繼承使用
4.可以定義抽象方法
為了給子類限定需要實現的規則
抽象的練習 :
每個員工Employee都具有屬性(姓名,工號,工資),行為 : 工作
程式設計師類: 屬性(姓名,工號,工資,獎金), 行為 : 工作(軟體開發)
測試工程師類 : 屬性(姓名,工號,工資), 行為 : 工作(軟體測試)
專案經理類 : 屬性(姓名,工號,工資,獎金),行為 : 工作(控制工作進度)
請設計出合適的類關係,並測試
程式碼
public abstract class Employee { // 姓名,工號,工資 private String name; String id; double salary; public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void work(); }
public class Employee_程式開發 extends Employee{ private double jiangjin; public Employee_程式開發(String name , String id, double salary, double jiangjin) { super(); this.jiangjin = jiangjin; this.id = id; setName(name); this.salary = salary; } public Employee_程式開發() { super(); } public double getJiangjin() { return jiangjin; } public void setJiangjin(double jiangjin) { this.jiangjin = jiangjin; } @Override public void work() { System.out.println(getName() +"---"+ id +"---"+ salary + "---"+jiangjin+"程式設計師做開發"); } }
public class Employee_測試工程師 extends Employee{ @Override public void work() { System.out.println("測試工作"); } }
public class TestEmployee { public static void main(String[] args) { Employee_程式開發 e1 = new Employee_程式開發("小張","007",15678.99,3200); e1.work(); Employee_測試工程師 e2 = new Employee_測試工程師(); e2.work(); } }
三、介面
3.1介面的概述
- 介面 : 一系列規則的集合, 介面中都是抽象方法
- 介面好處:
因為介面中全部都是抽象方法, 抽象方法只方法的宣告, 方法功能的宣告和方法的實現分離, 讓型別與型別之間的耦合度(關聯度)降低
3.2介面的定義
- 介面的定義 :
使用關鍵字 interface : 用於定義出介面型別
修飾符 interface 介面名{
// 抽象方法(隨著JDK版本的推進, 介面中不僅僅只有抽象方法,目前學習中,以抽象方法為學習重點,JDK8新特性,講解介面中的其他方法定義)
}
程式碼
public interface MyInter { // 定義抽象方法 public abstract void fun(); public abstract boolean equalDouble(double d, double d1); }
3.3介面的特點
- 介面中的方法都是抽象方法
- 介面不能例項化物件(不能new物件)
介面需要一個實現類, 將介面中的所有抽象方法重寫,通過建立實現類物件,呼叫重寫方法
3.類與介面之間的關係:實現關係 implements (與類和類之間的繼承extends關係非常相似)
舉例 : interface MyInter{}
class MyInterImpl implements MyInter{
// 將介面中的抽象方法全部重寫;
}
4.介面實現類的前途:
1)如果實現類將介面中的所有抽象方法全部重寫,那麼這個實現類可以正常使用
2)如果實現類沒有將介面中的所有抽象方法全部重寫, 那麼這個實現類是抽象類, 抽象類不能例項化物件
3.4介面中的成員
- 成員常量 : 介面中的所有成員變數都是常量, 因為介面中的成員變數有預設修飾, public static final, 寫出修飾或者不寫,以及寫出修飾符的一部分, 預設修飾不變
- 介面中無法定義構造方法: 因為介面中沒有成員變數
- 抽象方法 : 有預設修飾符, public abstract