一.抽象類
1.啥是抽象類
用專業語言描述就是:如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類
當然這話說的也很抽象,所以我們來用人話來解釋一下抽象類
拋開編程語言這些,就以現實舉例,我說貓的話,你頭腦能馬上浮現一只貓的具象,我說狗的話,你頭腦能馬上浮現一條狗的具象,但是當我說動物的時候,你頭腦是不能浮現動物的具象,或許頭腦里一會閃過雞鴨魚這些動物的樣子,過一會又會閃過牛馬羊這些動物的樣子,也就是說,你找不到一個具象能夠說動物具象化的樣子就是這個具象,所以我們稱動物就是一個抽象類。當然我們也可以繼續往下再抽象,比如狗,又分為各種各樣的狗,哈士奇,柴犬,斗牛犬等等,這時狗又可以被稱為抽象類,如此類推,可以繼續細分抽象類。所以在實際開發中,我們將什么看作為抽象類,注意還是要以實際情況為準
2.抽象類的構成結構
3.抽象類知識點
1.抽象類不能直接實例化對象,也就是說不能通過new 類名()來創建對象
2.被abstract修飾的類就是抽象類,因為是類,所以抽象類跟普通類的基本結構沒什么區別,唯一的區別就是多了抽象方法區
3.抽象類的訪問修飾符不能用private,抽象方法也是一樣不能用private
4.抽象方法也就是被abstract修飾的方法,所以abstract不僅可以修飾類,還可以修飾方法
5.抽象方法是不能被實現的,也就是說只能在這里寫個:修飾符? 返回類型? ?方法名(參數);
6.抽象方法不能被final和static修飾
7.抽象類中不一定要有抽象方法,但有抽象方法的一定是抽象類
8.抽象類必須被繼承,如果子類不重寫抽象類中的抽象方法,否則子類也是抽象類,必須用abstract修飾
現在我們來理解一下這些知識
1.為什么不能實例化對象?原因就如我們剛剛解釋什么是抽象類里一樣,我說動物,你不能夠找出一個具象說它就是動物的具象化,因為動物是有能跑能飛的,你如果說狗,但是狗不會飛,所以狗不能把動物這個抽象類全部描繪清楚,相當于數學里的包含關系,如圖
2.抽象類生來就是為了被繼承而誕生的,抽象類的作用就是將許多對象的共性集合起來,然后將這些共性變成抽象方法,比如吃飯,但是不同動物吃的不一樣,狗吃狗糧,貓吃貓糧,牛吃草,虎吃肉,但它們這些行為整體歸納起來還是就兩個字:吃飯。所以我們將這些共性放在抽象類里,繼承給某個具體對象時,它能根據自身情況實現里面的方法,這也是多態的概念——即不同對象去完成時會產生不同的狀態
3.所以抽象類天生就是當父親的料,也就是說它是父類圣體,幾乎可以看到抽象類就知道它是父類了,所以要想使用父類里的東西,那么它的訪問權限符肯定不能是private,那不然子類怎么去實現父類的抽象方法,就相當于一個人把遺產設置為private私人的,活的時候這遺產誰都不給用,那么他就算是死了,這遺產也要連著他一起都燒了,那還怎么讓子孫去繼承這個遺產,所以不能用private修飾抽象類(用重寫規則里的“子類重寫方法的訪問權限不能比父類中被重寫方法的訪問權限更低”也說得通,因為private是最低的訪問權限了,沒有比private更低的訪問權限了)
4.因為抽象方法在抽象類里是不能被實現的,所以它注定是要子類被重寫的,既然要被重寫了,就不能再加final(final修飾變量或字段,表示變為了常量;修飾類,表示此類不能被繼承;修飾方法,表示該方法不能被重寫),static也是修飾方法表示此方法不能被重寫,就好比嘴上說一套,私底下又一套,嘴上說大家快來重寫我的抽象方法,結果私底下又給自己的抽象方法加上final或static不讓這個抽象方法被重寫
5.子類繼承了抽象類后,子類可以重寫父類中的方法,也可以不重寫父類中的方法,如果不重寫,那么子類也就變成了抽象類,于是又開始新的一輪繼承,就相當于從祖先傳下來了一個未解的秘密,如果這一代人沒把這個秘密解出來,那么就傳給下一代人解,直到這個秘密被解出來為止,所以會出現不同情況,一種是一開始有許多抽象方法,但每一代都實現幾個抽象方法,如此類推,另一種是一開始有許多抽象方法,但每一代不僅不實現抽象方法,還在自己這一代再添加一些抽象方法,總的概括來說,就是父債子償,出來混總該要還的
6.既然核心就是要重寫父類里的方法,那么為什么一定要用抽象類呢,普通類也能被重寫呀,確實如此,用普通類也能實現上述一切要求,但是使用抽象類相當于多了一重編譯器的校驗,如果有一天腦袋突然糊涂了,把該重寫的方法沒有進行重寫,那么運行出來結果就會出錯,這時候又要在所有的代碼里面找錯誤,如果我們使用抽象類,就可以在我們這種犯糊涂的時候進行報錯,讓我們盡早發現問題。很多語法存在的意義就是為了“預防出錯”,像之前的final也是類似,如果我們給不想被修改的變量加上final,那么當我們不小心修改這個變量時,編譯器就會報錯,及時提醒我們。
所以充分利用編譯器的校驗,在實際開發中是非常有意義的
4.抽象類的例子
abstract class Animal{//抽象方法區abstract public void eat();abstract void speak();//其他區public String name;
}
class Dog extends Animal{public Dog(String name){this.name=name;}@Override //利用注解也能利用編譯器的檢查優勢,提高開發效率public void eat(){System.out.println(name+"吃狗糧");}@Overridepublic void speak(){System.out.println(name+"汪汪汪");}
}
class Cat extends Animal{public Cat(String name){this.name=name;}@Overridepublic void eat(){System.out.println(name+"吃貓糧");}@Overridepublic void speak(){System.out.println(name+"喵喵喵");}
}
public class Test {public static void main(String[] args) {Dog dog=new Dog("旺財");Cat cat=new Cat("小貓");dog.eat();dog.speak();cat.eat();cat.speak();}
}
二.接口
1.啥是接口
用專業語言解釋:多個類的公共規范,是一種引用數據類型
用人話來說,其實和抽象類非常相似,也是將許多對象的共性放在接口里,然后每個對象重寫接口里的抽象方法,實現多態。那么它存在的意義是什么呢?就要說回抽象類了,因為抽象類是用extends來繼承,變成父類子類的關系,但是在Java里面,只能實現單繼承,不支持多繼承,所以為了解決這個問題,接口就誕生了。所以就是為了一個類可以實現多個接口。
2.接口的構成結構
3.接口知識點
1.同抽象類一樣,接口也是不能被new()創建對象的,即使接口類型是一種引用類型
2.被interface修飾的就是接口,因為接口屬于引用類型,不屬于類,所以前面沒有class了
3.如上圖所示,接口中的方法都是抽象方法,即系統默認都是public abstract修飾的,也就是說,接口中的方法是不能在接口里面實現的,同時因為public abstract是系統默認修飾的,所以提高代碼簡潔性,一般都是不寫的(例如阿里的編碼規范中就要求不寫public abstract)
4.如果一定要實現接口中的方法,用default或static修飾,那么可以有具體的實現(這也是與抽象類不同的地方,抽象類即使加了default和static也不能被實現)
5.同抽象類一樣,接口不能被private修飾,里面的抽象方法也不能被private修飾
6.重寫接口中的方法不能使用默認的訪問權限,因為重寫規則里的“子類重寫方法的訪問權限不能比父類中被重寫方法的訪問權限更低”可得,接口中的方法默認是public,所以也只能用public來重寫接口中的方法
7.如上圖所示,接口中的變量系統默認用public static final修飾,所以即使不寫,也是被隱式指定的
8.接口中不能有靜態代碼塊和構造方法
9.接口雖然不是類,但是接口編譯完成后字節碼文件的后綴格式也是.class
10.與繼承extends不同,類連接接口用implements
11.同抽象類一樣,如果一個類連接接口后,如果不想實現接口里的抽象方法,那么這個類就要定義為抽象類,然后繼承給其他類,如此循環繼承,直到抽象方法全部被實現才可以不變為抽象類
12.接口名一般以大寫i為首字母命名
13.如果一個類既需要繼承又需要連接接口,那么必須先extends再implements
4.接口的例子
class Animal{protected String name;public Animal(String name){this.name=name;}
}
interface IFlying{void fly(); //省略public abstract,提高代碼簡潔性
}
interface IRunning{void run();
}
interface ISwimming{void swim();
}
class Cat extends Animal implements IRunning{ //先extends再implementspublic Cat(String name){super(name); //子類實例化前必須先初始化父類}@Override //添加注解,利用編譯器的檢查優勢,提高開發效率public void run(){ //必須用public才能重寫System.out.println(this.name+"正在用四條腿跑");}
}
class Duck extends Animal implements IRunning,IFlying,ISwimming{ //實現多接口public Duck(String name){super(name); //子類實例化前必須先初始化父類}@Overridepublic void run(){System.out.println(this.name+"正在用兩條腿跑");}@Overridepublic void fly(){System.out.println(this.name+"正在用翅膀飛");}@Overridepublic void swim(){System.out.println(this.name+"正在漂在水上");}
}
public class Test {public static void main(String[] args) {Cat cat=new Cat("neko");Duck duck=new Duck("唐老鴨");cat.run();duck.run();duck.fly();duck.swim();}
}