Java進階基礎:繼承的實現,方法重寫注意事項,方法過載與重寫的區別,抽象類,程式碼塊
1. 繼承
1.1 繼承的實現(掌握)
-
繼承的概念
-
繼承是面向物件三大特徵之一,可以使得子類具有父類的屬性和方法,還可以在子類中重新定義,以及追加屬性和方法
-
-
實現繼承的格式
-
繼承通過extends實現
-
格式:class 子類 extends 父類 { }
-
舉例:class Dog extends Animal { }
-
-
-
繼承帶來的好處
-
繼承可以讓類與類之間產生關係,子父類關係,產生子父類後,子類則可以使用父類中非私有的成員。
-
-
示例程式碼
public class Fu {
public void show() {
System.out.println("show方法被呼叫");
}
}
public class Zi extends Fu {
public void method() {
System.out.println("method方法被呼叫");
}
}
public class Demo {
public static void main(String[] args) {
//建立物件,呼叫方法
Fu f = new Fu();
f.show();
Zi z = new Zi();
z.method();
z.show();
}
}
1.2 繼承的好處和弊端(理解)
-
繼承好處
-
提高了程式碼的複用性(多個類相同的成員可以放到同一個類中)
-
提高了程式碼的維護性(如果方法的程式碼需要修改,修改一處即可)
-
-
繼承弊端
-
繼承讓類與類之間產生了關係,類的耦合性增強了,當父類發生變化時子類實現也不得不跟著變化,削弱了子類的獨立性
-
-
繼承的應用場景:
-
使用繼承,需要考慮類與類之間是否存在is..a的關係,不能盲目使用繼承
-
is..a的關係:誰是誰的一種,例如:老師和學生是人的一種,那人就是父類,學生和老師就是子類
-
-
1.3. Java中繼承的特點(掌握)
-
Java中繼承的特點
-
Java中類只支援單繼承,不支援多繼承
-
錯誤範例:class A extends B, C { }
-
-
Java中類支援多層繼承
-
-
多層繼承示例程式碼:
public class Granddad {
public void drink() {
System.out.println("爺爺愛喝酒");
}
}
public class Father extends Granddad {
public void smoke() {
System.out.println("爸爸愛抽菸");
}
}
public class Mother {
public void dance() {
System.out.println("媽媽愛跳舞");
}
}
public class Son extends Father {
// 此時,Son類中就同時擁有drink方法以及smoke方法
}
2. 繼承中的成員訪問特點
2.1 繼承中變數的訪問特點(掌握)
在子類方法中訪問一個變數,採用的是就近原則。
-
子類區域性範圍找
-
子類成員範圍找
-
父類成員範圍找
-
如果都沒有就報錯(不考慮父親的父親…)
-
示例程式碼
class Fu {
int num = 10;
}
class Zi {
int num = 20;
public void show(){
int num = 30;
System.out.println(num);
}
}
public class Demo1 {
public static void main(String[] args) {
Zi z = new Zi();
z.show(); // 輸出show方法中的區域性變數30
}
}
2.2 super(掌握)
-
this&super關鍵字:
-
this:代表本類物件的引用
-
super:代表父類儲存空間的標識(可以理解為父類物件引用)
-
-
this和super的使用分別
-
成員變數:
-
this.成員變數 - 訪問本類成員變數
-
super.成員變數 - 訪問父類成員變數
-
-
成員方法:
-
this.成員方法 - 訪問本類成員方法
-
super.成員方法 - 訪問父類成員方法
-
-
-
構造方法:
-
this(…) - 訪問本類構造方法
-
super(…) - 訪問父類構造方法
-
2.3 繼承中構造方法的訪問特點(理解)
注意:子類中所有的構造方法預設都會訪問父類中無參的構造方法
子類會繼承父類中的資料,可能還會使用父類的資料。所以,子類初始化之前,一定要先完成父類資料的初始化,原因在於,每一個子類構造方法的第一條語句預設都是:super()
問題:如果父類中沒有無參構造方法,只有帶參構造方法,該怎麼辦呢?
1. 通過使用super關鍵字去顯示的呼叫父類的帶參構造方法
2. 子類通過this去呼叫本類的其他構造方法,本類其他構造方法再通過super去手動呼叫父類的帶參的構造方法
注意: this(…)super(…) 必須放在構造方法的第一行有效語句,並且二者不能共存
2.4 繼承中成員方法的訪問特點(掌握)
通過子類物件訪問一個方法
-
子類成員範圍找
-
父類成員範圍找
-
如果都沒有就報錯(不考慮父親的父親…)
2.5 super記憶體圖(理解)
-
物件在堆記憶體中,會單獨存在一塊super區域,用來存放父類的資料
2.6 方法重寫(掌握)
-
1、方法重寫概念
-
子類出現了和父類中一模一樣的方法宣告(方法名一樣,引數列表也必須一樣)
-
-
2、方法重寫的應用場景
-
當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容
-
-
3、Override註解
-
用來檢測當前的方法,是否是重寫的方法,起到【校驗】的作用
-
2.7 方法重寫的注意事項(掌握)
-
方法重寫的注意事項
-
私有方法不能被重寫(父類私有成員子類是不能繼承的)
-
子類方法訪問許可權不能更低(public > 預設 > 私有)
-
靜態方法不能被重寫,如果子類也有相同的方法,並不是重寫的父類的方法
-
示例程式碼
public class Fu {
private void show() {
System.out.println("Fu中show()方法被呼叫");
}
void method() {
System.out.println("Fu中method()方法被呼叫");
}
}
public class Zi extends Fu {
/* 編譯【出錯】,子類不能重寫父類私有的方法*/
2.8 許可權修飾符 (理解)
2.9 黑馬資訊管理系統使用繼承改進 (掌握)
-
需求
把學生類和老師類共性的內容向上抽取,抽取到出一個 Person 父類,讓學生類和老師類繼承 Person 類
-
實現步驟
-
抽取Person類
-
優化StudentController類中,inputStudentInfo方法,將setXxx賦值方式,改進為構造方法初始化
注意:直接修改這種操作方式,不符合我們開發中的一個原則
開閉原則 ( 對擴充套件開放對修改關閉 ) : 儘量在不更改原有程式碼的前提下以完成需求
解決:重新建立一個OtherStudentController類
編寫新的inputStudentInfo方法
-
根據StudentController類、OtherStudentController類,向上抽取出BaseStudentController類 再讓StudentController類、OtherStudentController類,繼承BaseStudentController類
-
-
程式碼實現
Person類及學生類和老師類
public class Person {
private String id;
private String name;
private String age;
private String birthday;
public Person() {
}
public Person(String id, String name, String age, String birthday) {
this.id = id;
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
// Student類
public class Student extends Person {
public Student() {
}
public Student(String id, String name, String age, String birthday) {
super(id, name, age, birthday);
}
}
// Teacher類
public class Teacher extends Person {
public Teacher() {
}
public Teacher(String id, String name, String age, String birthday) {
super(id, name, age, birthday);
}
}BaseStudentController類
public abstract class BaseStudentController {
// 業務員物件
private StudentService studentService = new StudentService();
private Scanner sc = new Scanner(System.in);
// 開啟學生管理系統, 並展示學生管理系統選單
public void start() {
//Scanner sc = new Scanner(System.in);
studentLoop:
while (true) {
System.out.println("--------歡迎來到 <學生> 管理系統--------");
System.out.println("請輸入您的選擇: 1.新增學生 2.刪除學生 3.修改學生 4.檢視學生 5.退出");
String choice = sc.next();
switch (choice) {
case "1":
// System.out.println("新增");
addStudent();
break;
case "2":
// System.out.println("刪除");
deleteStudentById();
break;
case "3":
// System.out.println("修改");
updateStudent();
break;
case "4":
// System.out.println("查詢");
findAllStudent();
break;
case "5":
System.out.println("感謝您使用學生管理系統, 再見!");
break studentLoop;
default:
System.out.println("您的輸入有誤, 請重新輸入");
break;
}
}
}
// 修改學生方法
public void updateStudent() {
String updateId = inputStudentId();
Student newStu = inputStudentInfo(updateId);
studentService.updateStudent(updateId, newStu);
System.out.println("修改成功!");
}
// 刪除學生方法
public void deleteStudentById() {
String delId = inputStudentId();
// 3. 呼叫業務員中的deleteStudentById根據id, 刪除學生
studentService.deleteStudentById(delId);
// 4. 提示刪除成功
System.out.println("刪除成功!");
}
// 檢視學生方法
public void findAllStudent() {
// 1. 呼叫業務員中的獲取方法, 得到學生的物件陣列
Student[] stus = studentService.findAllStudent();
// 2. 判斷陣列的記憶體地址, 是否為null
if (stus == null) {
System.out.println("查無資訊, 請新增後重試");
return;
}
// 3. 遍歷陣列, 獲取學生資訊並列印在控制檯
System.out.println("學號\t\t姓名\t年齡\t生日");
for (int i = 0; i < stus.length; i++) {
Student stu = stus[i];
if (stu != null) {
System.out.println(stu.getId()