Java抽象類\多態(tài)
1抽象類什么時候使用?
當(dāng)某個父類只是知道子類應(yīng)該包含怎么樣的方法,但是無法準(zhǔn)確知道子類如何實現(xiàn)這些方法。
比如一個圖形類應(yīng)該有一個求周長的方法,但是不同的圖形求周長的算法不一樣。那該怎么辦呢?
(分析事物時,發(fā)現(xiàn)了共性內(nèi)容,就出現(xiàn)向上抽取。會有這樣一種特殊情況,就是方法功能聲明相同,但方法功能主體不同。那么這時也可以抽取,但只抽取方法聲明,不抽取方法主體。那么此方法就是一個抽象方法。)
2抽象類: 包含抽象方法的類,一定是抽象類,,使用 abstract 修飾的類,是抽象類
抽象類的特點:
1,抽象類與抽象方法都必須使用 abstract 來修飾
2,抽象類不能直接創(chuàng)建對象(意義),原因:調(diào)用抽象方法沒有意義。
3,抽象類中可以有抽象方法,也可以沒有抽象方法(面試問題)
4,抽象類的子類(繼承)
a,實現(xiàn)了抽象方法的具體類,,只有覆蓋了抽象類中所有的抽象方法后,其子類才可以創(chuàng)建對象。
b,抽象類,否則該子類還是一個抽象類,子類不可以創(chuàng)建對象。
抽象類面試題://抽象類中是否可以沒有抽象方法?如果可以,那么,該類還定義成抽象類有意義嗎?為
什么?可以沒有抽象方法,有意義,不會讓其他人直接創(chuàng)建該類對象
3抽象方法
抽象方法: 方法只有聲明部分,沒有方法體.
抽象方法定義的格式:
public abstract 返回值類型 方法名(參數(shù));
抽象類定義的格式:
public abstract void class 類名 {
}
4 抽象類的細(xì)節(jié)問題:
1)、抽象類一定是個父類?是的,因為不斷抽取而來的。
2)、抽象類中是否可以不定義抽象方法。
是可以的,那這個抽象類的存在到底有什么意義呢?不讓該類創(chuàng)建對象,方法可以直接讓子類去使用
3)、抽象關(guān)鍵字 abstract 不可以和哪些關(guān)鍵字共存?
①private:私有的方法子類是無法繼承到的,也不存在覆蓋,而 abstract 和 private 一起使用修飾方法,abstract 既要子類去實現(xiàn)這個方法,而 private 修飾子類根本無法得到父類這個方法?;ハ嗝堋?/p>
②final.
③static.
eg:
抽象類Employee
package com.hello.abstrsct;
public abstract class Employee {
public abstract void working();//聲明抽象類方法
}
抽象類PhpCoder
package com.hello.abstrsct;
public class PhpCoder extends Employee {
public void working() {
System.out.println("java");
}
}
測試
package com.hello.abstrsct;
import org.junit.Test;
public class Demo {
@Test
public void test() {
PhpCoder p=new PhpCoder();//實例化子類
p.working();
}
}
多態(tài)
現(xiàn)實事物經(jīng)常會體現(xiàn)出多種形態(tài),如學(xué)生,學(xué)生是人的一種,則一個具體的同學(xué)張三既是學(xué)生也是人,即出現(xiàn)兩種形態(tài)。如 Student 類繼承了 Person 類,一個 Student 的對象便既是 Student,又是 Person。那么一個 Student 對象既可以賦值給一個 Student 類型的引用,也可以賦值給一個 Person 類型的引用。
多態(tài)使用的前提:
1,有繼承或者實現(xiàn)關(guān)系
2,要方法重寫
3,父類引用指向子類對象
多態(tài)特點:
①最終多態(tài)體現(xiàn)為父類引用變量可以指向子類對象。
②多態(tài)的前提是必須有子父類關(guān)系或者類實現(xiàn)接口關(guān)系,否則無法完成多態(tài)。
③在使用多態(tài)后的父類引用變量調(diào)用方法時,會調(diào)用子類重寫后的方法。
多態(tài)的定義格式:就是父類的引用變量指向子類對象
父類類型 變量名 = new 子類類型();
變量名.方法名();
分類:
①普通類多態(tài)定義的格式
父類 變量名 = new 子類();
如: class Fu {}
class Zi extends Fu {}
//類的多態(tài)使用
Fu f = new Zi();//實例化子類
②抽象類多態(tài)定義的格式
抽象類 變量名 = new 抽象類子類();
如: abstract class Fu {
public abstract void method();
}
class Zi extends Fu {
public void method(){
System.out.println(“重寫父類抽象方法”);
}
}
//類的多態(tài)使用
Fu fu= new Zi();//實例化抽象子類
③接口多態(tài)定義的格式
接口 變量名 = new 接口實現(xiàn)類();
如:
//接口
interface Fu {
public abstract void method();
}
接口實現(xiàn)類implements
class Zi implements Fu {
public void method(){
System.out.println(“重寫接口抽象方法”);
}
}
//接口的多態(tài)使用
Fu fu = new Zi();//實例化接口實現(xiàn)類
成員變量在使用上有沒有變化,有的
package com.hello.abstrsct;
public class Fu {
int num = 4;
void show() {
System.out.println("Fu show num");
}
}
子類
package com.hello.abstrsct;
public class Zi extends Fu {
int num = 5;
public void show() {
System.out.println("Zi show num");
}
}
多態(tài)測試
public class Test1 {
public static void main(String[] args) {
Fu f = new Zi();
//f.show();//顯示子類的
Zi zi=new Zi();
System.out.println(zi.num);//5
System.out.println(f.num);//4
}
成員方法在使用上有沒有變化,有的
public static void main(String[] args) {
Fu f = new Zi();//實例化子類
f.show();//顯示子類的
}
instanceof 關(guān)鍵字
來判斷某個對象是否屬于某種數(shù)據(jù)類型。如學(xué)生的對象屬于學(xué)生類,學(xué)生的對象也屬于人類。
使用格式:
boolean b = 對象 instanceof 數(shù)據(jù)類型;
如
Person p1 = new Student(); // 前提條件,學(xué)生類已經(jīng)繼承了人類
boolean flag = p1 instanceof Student; //flag 結(jié)果為 true
boolean flag2 = p2 instanceof Teacher; //flag 結(jié)果為 false
多態(tài)的轉(zhuǎn)型分為向上轉(zhuǎn)型與向下轉(zhuǎn)型兩種:
向上轉(zhuǎn)型:當(dāng)有子類對象賦值給一個父類引用時,便是向上轉(zhuǎn)型,多態(tài)本身就是向上轉(zhuǎn)型的過程。
使用格式:
父類類型 變量名 = new 子類類型();
如:Person p = new Student();
向下轉(zhuǎn)型:一個已經(jīng)向上轉(zhuǎn)型的子類對象可以使用強制類型轉(zhuǎn)換的格式,將父類引用轉(zhuǎn)為子類引用,這個過程是向下轉(zhuǎn)型。如果是直接創(chuàng)建父類對象,是無法向下轉(zhuǎn)型的!
使用格式:
子類類型 變量名 = (子類類型) 父類類型的變量;
Person p = new Student();
如:Student stu = (Student) p; //變量 p 實際上指向 Student 對象
!!如果是調(diào)用子類獨有的功能時,必須要向下轉(zhuǎn)型,才能調(diào)用.
//描述動物類,并抽取共性 eat 方法
abstract class Animal {
abstract void eat();
}
// 描述狗類,繼承動物類,重寫 eat 方法,增加 lookHome 方法
class Dog extends Animal {
void eat() {
System.out.println("啃骨頭");
}
void lookHome() {
System.out.println("看家");
}
}
// 描述貓類,繼承動物類,重寫 eat 方法,增加 catchMouse 方法
class Cat extends Animal {
void eat() {
System.out.println("吃魚");
}
void catchMouse() {
System.out.println("抓老鼠");
}
}
測試
public class Test {
public static void main(String[] args) {
Animal a = new Dog(); //多態(tài)形式,創(chuàng)建一個狗對象
a.eat(); // 調(diào)用對象中的方法,會執(zhí)行狗類中的 eat 方法
// a.lookHome();//使用 Dog 類特有的方法,需要向下轉(zhuǎn)型,不能直接使用
// 為了使用狗類的 lookHome 方法,需要向下轉(zhuǎn)型
// 向下轉(zhuǎn)型過程中,可能會發(fā)生類型轉(zhuǎn)換的錯誤,即 Class Cast Exception 異常
// 那么,在轉(zhuǎn)之前需要做健壯性判斷
if( !a instanceof Dog){ // 判斷當(dāng)前對象是否是 Dog 類型
System.out.println("類型不匹配,不能轉(zhuǎn)換");
return;}
}