java基礎知識整理(7)——繼承與抽象
一、繼承
1、概述
多個類中存在相同屬性和行為時,將這些相同的內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行為,只要繼那個類即可。多個類可以稱為子類,單獨這個類稱為父類或者超類。子類可以直接訪問父類中的非私有的屬性和行為。
2、特點
A:Java只支援單繼承,不支援多繼承(子類呼叫父類方法的不確定性)。但是它支援多層繼承(介面與介面之間可以存在多繼承)
B:父類有的,子類也有,而且子類可以改變(更改父類的屬性值,重寫父類的成員方法),父類沒有的子類也可以進行增加。
C:父類的屬性和方法可以被繼承,但是構造方法不能被繼承,子類的構造方法隱式的呼叫父類的無參構造方法,當父類沒有無參構造方法時,子類需要使用super來顯示的呼叫父類的構造方法。
3、舉例
-------學生類繼承了人類,擁有了人類的成員變數(name和age)和成員方法(eat和sleep方法)
class Person{
String name;
int age;
Person(){}
public void sleep(){
System.out.println("睡覺");
}
public void eat(){
System.out.println("吃飯");
}
}
class Student extends Person{//學生繼承人類
String sid;//學號
public void study(){
System.out.println("我寧願做一頭快樂的豬");
}
}
4、研究繼承後 Fu和Zi的關係。
A:成員變數
**子類直接繼承了本身沒有的成員變數。
**當子類中有和父類同名的成員變數時。在方法中列印的是子類自己的。
**當子類方法中有區域性變數和成員變數同名,在方法中列印的是區域性變數。
也就是說:先在區域性範圍找,其次在本類中找,最後在父類中找。如果找到,立馬輸出。
如果找不到,就報錯。
B:成員方法
**父類中的方法和子類中沒有同名的情況。子類就把父類的方法直接繼承過來使用。
**子類中存在了和父類同名的方法時,子類就會去呼叫子類中的方法。而且這種現象
在java中稱為重寫(override),複寫,覆蓋。
過載(overload)與重寫(override)的區別:
過載(overload):
**在同一個類中。
**方法名相同,引數列表不同。
重寫(override)
**存在於子父類當中。
**方法的宣告一致。(名稱和引數)
**子類的訪問許可權不能低於父類的訪問許可權。
簡單說:用子類物件呼叫方法時,首先子子類中找,其次在父類中找。如果找到,會直接操作。如果找不到,就報錯。
父類靜態方法只能被子類靜態方法重寫。(一般不會出現這種情況,靜態屬於類不再屬於物件)
注意:
**父類中的私有方法不可以被覆蓋。
**在子類覆蓋方法中,要想繼續使用被覆蓋的父類方法可以通過super.方法名獲取。
格式:super.方法名();
This代表本類物件的引用。
Super代表父類所屬的空間,並不是一個物件。
C:構造方法
**子類中所有的建構函式預設都會訪問父類中空引數的建構函式
**因為每一個建構函式的第一行都有一條預設的語句super();
this() 代表本類的無參構造
super() 代表父類的無參構造
**當父類中沒有空引數的建構函式時,子類的建構函式必須通過this或者super語句指定要訪問的建構函式。
為什麼子類的建構函式都要去預設訪問父類的建構函式?
因為子類繼承了父類,可以訪問父類中的已有的一些屬性,在子類進行例項化的時候必須要為父類中的屬性進行分配空間,並要進行初始化,所以必須要訪問一次父類的建構函式,看看父類是如何對其屬性進行初始化的,所以子類要例項化物件時,必須要先看父類的初始化過程。
結論:父類的建構函式,既可以給本類物件初始化,也可以給子類物件初始化。
5、什麼時候使用繼承?
A:當某個事物是另一個事物的一種的時候,就用繼承。
B:如何判斷一個事物是另一個事物的一種?
對於A類和B類。
我們可以假設它們存在著繼承關係。比如:A extends B
如果A是B的一種,那麼繼承成立。他們就具有繼承關係。否則,繼承關係不成立。
二、final
1、final定義
最終的意思。
2、使用場景及特點
可以用於修飾類,修飾成員變數,成員方法。
A:final修飾的類不能被繼承。
B:fainl修飾的成員方法不能被重寫。
C:final修飾的成員變數是一個常量。
3、和變數宣告的區別
final double PI = 3.14;
A:多了一個關鍵字修飾。
B:變數名大寫。
C:值不能被改變。
注意:用final修飾的變數必須先賦初始值再操作,否則編譯失敗。
三、抽象類
1、概述
**抽象就是從多個事物中將共性的,本質的內容抽取出來。
**Java中可以定義沒有方法體的方法,該方法的具體實現由子類完成,該方法稱為抽象方法,包含抽象方法的類就是抽象類。
**多個物件都具備相同的功能,但是功能具體內容有所不同,那麼在抽取過程中,只抽取了功能定義,並未抽取功能主體,
那麼只有功能宣告,沒有功能主體的方法稱為抽象方法。
2、特點
**抽象類和抽象方法都必須用abstract關鍵字修飾。
**抽象方法一定要在抽象類中。
**一個類繼承了抽象類:
要麼該類實現抽象類中的所有抽象方法。
要麼該類實現部分抽象方法或者根本不實現任何抽象方法,這個時候需要把自身定義為抽象類。
**抽象類不能夠被例項化。也就是說不可以通過new關鍵字建立物件。
為什麼抽象類不能被例項化?
因為抽象類中有抽象方法,你建立物件後,別人呼叫抽象方法是沒有任何意義的。
**有人說:因為抽象類沒有構造方法是錯誤的。
那麼抽象類的構造有意義嗎?有。
抽象類本身是一個類,所有它有構造方法。它不能例項化不代表它的構造方法沒有意義。它可以用於為子類物件進行例項化。
3、應用
僱員示例
需求:公司中程式設計師有姓名,工號,薪水,工作內容。
專案經理除了有姓名,工號,薪水,還有獎金,工作內容。對給出需求進行資料建模。
資料建模:就是把我們給出的事物描述出來。說白了就是把類給設計出來。
我想讓專案經理繼承程式設計師。
這是時候,我們說專案經理的是程式設計師的一種,發現可以。
但是呢,分析又有小問題了:專案經理的工作內容和程式設計師不一樣。
不管怎麼說:程式設計師和經理都是公司的員工。
所以,我們分析出一個員工類,來描述共性的內容。
然後把程式設計師和經理具體的描述下。
程式碼:
abstract class Employee{
String name;//姓名
String id;//工號
double salary;//薪水
Employee(){}
Employee(String name,String id,double salary){
this.name = name;
this.id = id;
this.salary = salary;
}
abstract void work();//工作內容
abstract void showInfo();//個人資訊
}
class Worker extends Employee{
Worker(){}
Worker(String name,String id,double salary){
super(name,id,salary);
}
void work(){
System.out.println("好好學習,天天向上");
}
void showInfo(){
System.out.println(name+" "+id+" "+salary);
}
}
class Manager extends Employee{
double bonus;//獎金
Manager(){}
Manager(String name,String id,double salary,double bonus){
super(name,id,salary);
this.bonus = bonus;
}
void work(){
System.out.println("想怎麼著能讓你更大的能量(更累,累並快樂著)");
}
void showInfo(){
System.out.println(name+" "+id+" "+salary+" "+bonus);
}
}
class AbstractDemo5 {
public static void main(String[] args) {
Worker w = new Worker("慈禧","cixi888",10000);
w.work();
w.showInfo();
Manager m = new Manager("李蓮英","lilianyin250",2000,16000);
m.work();
m.showInfo();
}
}
4、細節
A:抽象類中是否有構造方法?
**因為抽象類它本身也是一個類,所以它有構造方法。
**雖然它不能夠被例項化,但是它的構造方法也是有用的。用於給子類做初始化。
B:抽象類中可不可以沒有抽象方法?
**可以的。
**有什麼用?讓類不能夠被例項化。在awt裡面有體現。
C:抽象關鍵字abstract不可以和哪些關鍵字共存?
**final 它修飾的方法不能被重寫。而這樣就和抽象產生了衝突。
***final abstract void show(); 這是不行的。
**private 它修飾內容只能在本類中被訪問。
***private abstract void show(); 這是不行的。
**static 它修飾的內容可以直接被類訪問,而訪問抽象的內容沒有意義。
***static abstract void show(); 這是不行的。