面向物件(13-1):抽象類
阿新 • • 發佈:2021-12-12
面向物件(13):抽象類
1、抽象的表述
我們之前所說的貓,狗,豬,羊駝,熊貓等等都是動物的具體的例子,而動物本身是一個抽象的概念,
而我們之前是將動物寫成了一個類,而類又可以建立物件,但是呢,實際上抽象的東西本身應該不能例項化,
並且動物這個概念中吃的方法,以及動物共有的方法本身也是一個不具體的方法,我們在今天之後,
把一個不具體的功能,叫做抽象方法,而如果說一個類中包含有抽象方法的時候,這個類叫做抽象類。
2、抽象類的特點
(1)抽象類和抽象方法 要用abstract關鍵字修飾
abstract修飾類:放在class前面 舉例: abstract class Animal3{} abstract修飾方法:放在訪問許可權修飾符的後面 舉例: public abstract void eat(); 抽象方法沒有方法體(沒有大括號{}),直接以分號結尾
(2)有抽象方法的一定是抽象類,但抽象類中不一定有抽象方法(抽象類中只含有具體的成員方法也是可以的);
具體的類中不能有抽象方法,否則會直接報錯
案例: //動物本身是抽象的概念,不能寫成具體的東西 //建立一個抽象類 abstract class Animal22{ //abstract修飾類的時候,abstract要放在class前面 //動物的吃也是一個抽象的,不能寫具體的怎麼吃 //建立一個動物吃的抽象方法 public abstract void eat();//abstract修飾方法的時候,abstract放在訪問許可權修飾符的後面 //而且抽象方法沒有方法體,大括號{}去掉 //建立一個具體實現方法 public void fun(){ System.out.println("這是抽象類中的具體實現的fun方法"); } } /* 抽象類中,既可以包含抽象方法,也可以包含具體實現的方法(非抽象方法),不會報錯 */ 錯誤案例: //建立一個具體的狗類 class Dog { //單獨在具體的類中建立抽象方法 public abstract void show();//這樣寫 會報錯 }
(3)如果繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法
錯誤案例: //建立一個具體的狗類,繼承抽象類Animal22 class Dog extends Animal22{ //這樣寫會直接報錯 } 正確案例:上面如果想要不報錯,要重寫抽象類所有的抽象方法 /建立一個具體的狗類,Animal22 class Dog extends Animal22{ //繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法 //重寫抽象類中的抽象方法,快捷鍵 游標放在類名上,按住Alt+Enter,選擇Implement methods回車 @Override public void eat() { System.out.println("狗吃肉");//自己新增一個輸出語句 }
如果是一個抽象類繼承抽象類,不需要重寫抽象類中的方法
//建立一個抽象類Demo1,來繼承抽象類Animal22
abstract class Demo1 extends Animal22{
//抽象類繼承抽象類,類中什麼也不寫,不會報錯
}
(4)抽象類不能被例項化(就是說在測試類中,不能直接建立物件來呼叫抽象類中具體的方法)
既然不能被例項化,那寫在抽象類中具體的方法怎麼去呼叫呢?抽象類如果建立呢?
即:利用多型的形式,通過具體的子類例項化去呼叫方法
案例:想要調取抽象類中的fun方法
//動物本身是抽象的概念,不能寫成具體的東西
//建立一個抽象類
abstract class Animal22{ //abstract修飾類的時候,abstract要放在class前面
//動物的吃也是一個抽象的,不能寫具體的怎麼吃
//建立一個抽象方法
public abstract void eat();//abstract修飾方法的時候,abstract放在訪問許可權修飾符的後面
//而且抽象方法沒有方法體,大括號{}去掉
//建立一個具體實現方法
public void fun(){
System.out.println("這是抽象類中的具體實現的fun方法");
}
}
//建立一個具體的狗類,繼承抽象類
class Dog extends Animal22{
//繼承抽象類的是一個具體的類,要重寫抽象類所有的抽象方法
//重寫抽象類中的抽象方法,快捷鍵 游標放在類名上,按住Alt+Enter,選擇Implement methods回車
@Override
public void eat() {
System.out.println("狗吃肉");//自己新增一個輸出語句
}
}
//測試類
public class AbstractDemo1 {
public static void main(String[] args) {
//抽象類中,不能直接建立抽象類物件,來調取抽象類中具體的方法
//要利用多型的形式,通過具體的子類例項化去呼叫方法
//使用抽象多型的形式建立物件(父類引用指向子類物件)
Animal22 a = new Dog();
a.fun();//可以呼叫抽象類中具體實現的fun方法
a.eat();//可以呼叫具體狗類中的eat方法
}
}
3、抽象類多型的案例
/*
在抽象的動物類中定義兩個抽象方法,吃飯和睡覺
分析:
1、建立一個抽象類:動物類
2、定義吃飯和睡覺的抽象方法
想要最終列印輸出吃飯和睡覺,必須建立具體的類來繼承抽象類,
然後通過使用抽象類多型建立物件(父類引用指向子類物件)
來調取具體的類中的方法
*/
//建立一個抽象類:動物類
abstract class Animal66{
//定義吃飯和睡覺抽象方法
public abstract void eat();
public abstract void sleep();
}
//建立一個具體的類來繼承抽象類
class Cat extends Animal66{
//繼承抽象類需要重寫抽象類的所有抽象方法 快捷鍵 Alt+Enter回車
@Override
public void eat() {
System.out.println("貓吃飯");
}
@Override
public void sleep() {
System.out.println("貓睡覺");
}
//我們自己給貓新增一個特有的方法:抓老鼠
public void catchMouse(){
System.out.println("貓抓老鼠");
}
}
//測試類
public class AbstractDemo2 {
public static void main(String[] args) {
//使用抽象多型建立物件
Animal66 a = new Cat();
//調取具體類中的抽象方法
a.eat();
a.sleep();
//如果想要調取具體類中特有的方法
//則需要多型向下轉型
Cat c =(Cat)a;
//向下轉型後再呼叫特有的方法
c.catchMouse();
}
}
4、抽象類的成員特點
(1)抽象類中的成員變數:可以是變數,也可以是常量
abstract class Animal{
public int a;
public final int b = 20;
}
(2)抽象類中的構造方法:有構造方法,但是抽象類不能例項化
那構造的意義是什麼呢?要想初始化子類,就必須先初始化父類,在繼承的關係中有用
abstract class Animal{
public int a;
//手動建立構造方法
Animal(){
a = 20;
System.out.println(a);
}
}
//建立一個具體的類繼承抽象 類
class Dog extends Animal{
}
//測試類
public class AbstractDemo{
public static void main(String[] args) {
//建立Dog類的物件
Dog d = new Dog();
}
}
執行結果是:
20
Process finished with exit code 0
/*
在具體的類中並沒有語句體,但是建立物件後仍可以輸出20;
這說明要想初始化子類,就必須先初始化父類,在繼承的關係中有用
所有執行的時候呼叫了抽象類的構造方法
*/
(3)抽象類中的成員方法
可以有抽象方法 限定子類必須完成某些動作;
也可以有非抽象方法 提高程式碼服用性