一.抽象類
1.定義
抽象類 = 普通類 + 抽象方法
抽象方法 = 聲明卻未實現的方法(沒有方法體)
注意:
(1)沒有方法體的方法不一定都是抽象方法哦,還有可能是本地方法;
(2)所有抽象方法要求使用abstract關鍵字來定義;抽象方法所在的類也必須使用abstract關鍵字來定義;
(3)抽象類中包含抽象方法,而抽象方法不包含方法體,即沒有具體實現。因此抽象類不能直接產生實例化對象;
下面來看一個抽象類的例子:
//抽象水果類
abstract class Fruit{
private String name;//屬性,水果名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void getFruitInfo();//抽象方法
}
其實說到這裏呢,我們會很發現,抽象類的最大特點是什麼呢?就是假如說我們有很多水果類,蘋果、芒果、火龍果...,它們都有水果名這個屬性,那麼都可以通過繼承抽象水果類來獲得父類的屬性,也可以在此基礎上擴展自己的特性;
來,看一個芒果
class mango extends Fruit{
@Override
public void getFruitInfo() {
System.out.println("Hello,我是芒小果");
}
}
看,抽象類是不是很棒呢。但是,Java中的繼承是單繼承哦,下面這種情況是不可以的。
2.抽象類使用原則
(1)所有抽象類必須有子類;
(2)抽象類的子類必須覆寫抽象類的所有抽象方法(子類不是抽象類),方法覆寫要注意權限問題;
(3)抽象類的對象可以通過對象多態性利用子類爲其實例化;
(4)private和abstract不能一起同時使用;
吶,一個經典的例子(在我心裏是經典哦):
abstract class Person{
private String name;//屬性
//普通方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽象方法
public abstract void getPersonInfo();
}
class Student extends Person{
@Override
public void getPersonInfo() {
System.out.println("I'm a student");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Student();//向上轉型
person.getPersonInfo();//子類覆寫的方法
}
}
輸出:
經典吧,哈哈哈,對,我就是一個小學生
3.抽象類的相關規定
(1)抽象類只是比普通類多了一些抽象方法而已;
抽象類中也有構造方法哦,並且子類也照樣遵循對象實例化流程。實例化子類時一定先調用父類構造方法。
栗子:在抽象類中定義構造方法
/**
* @Author:Star
* @Date:Created in 15:55 2019/10/14
* @Description:
*/
abstract class Person{
private String name;//屬性
public Person() {//構造方法
System.out.println("***Person***");
}
//普通方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//抽象方法
public abstract void getPersonInfo();
}
class Student extends Person{
public Student() {//構造方法
System.out.println("###Student###");
}
@Override
public void getPersonInfo() {
System.out.println("I'm a student");
}
}
public class Test {
public static void main(String[] args) {
new Student();
}
}
輸出:
另外,補充一點點,如果父類沒有無參構造,那麼子類構造必須使用super明確指出使用父類哪個構造方法。
栗子:
/**
* @Author:Star
* @Date:Created in 16:22 2019/10/14
* @Description:
*/
abstract class A{
public A(){//3.調用父類構造
this.print();//4.調用被子類覆寫的方法
}
public abstract void print();
}
class B extends A{
private int num = 100;
public B(int num){//2.調用子類實例化對象
super();//3.隱含的一行語句,實際要先調用父類構造
this.num = num;//7.爲類中屬性初始化
}
@Override
public void print() {//5.此時子類對象的屬性還沒有被初始化
System.out.println(this.num);//6.對應其數據類型的默認值
}
}
public class Test01 {
public static void main(String[] args) {
new B(30);//1.實例化子類對象
}
}
程序的執行順序就是按照1,2,...,7來執行的,所以要注意哦,即輸出爲0(對象屬性對應數據類型的默認值);
輸出:
(2)抽象類可以不定義任何抽象方法,但此時仍然無法直接實例化對象;
(3)final與abstract不能同時出現;private與abstract也不能同時出現;
抽象類一定不能使用final聲明,因爲使用final聲明的類不允許有子類;而抽象類必須有子類;相應的,抽象方法也不能使用private定義,因爲抽象方法必須要能被覆寫。
(4)抽象類也分爲外部抽象類與內部抽象類。內部抽象類中也可以使用static定義來描述外部抽象類;
內部抽象類的抽象方法與外部抽象類的抽象方法無關。
當前直接繼承哪個抽象類,就覆寫其抽象方法(若直接繼承外部抽象類,則只需要覆寫外部抽象類的所有抽象方法即可
栗子:內部抽象類
abstract class A{
public abstract void printA();
abstract class B{
public abstract void printB();
}
}
class X extends A{
public void printA(){}
class Y extends B{
public void printB(){}
}
}
如果在外部抽象類中使用了static那就是語法錯誤,但是內部抽象類允許使用static;
栗子:使用了static的內部抽象類
abstract class A{
public abstract void printA();
static abstract class B{
public abstract void printB();
}
}
class X extends A,B{
public void printB(){}
}
二.接口
1.定義
接口 = 抽象方法 + 全局變量(JDK8以前)
栗子:接口定義
interface IFruit{
public static final String name = "水果";//全局變量
public abstract void print();//抽象方法
}
注意:
(1)接口優先原則;即可使用接口又可使用抽象類時,優先考慮使用接口
(2)使用interface定義接口,爲了區分接口,在所有接口前面追加字母I;
(3)子類實現接口,使用implements關鍵字,並且子類可以同時實現多個接口(接口多繼承);
(4)子類必須覆寫所有抽象方法。子類命名一般使用Impl結尾;
(5)多個接口若有共同子類,可以通過子類進行相互轉換(父接口之間的相互轉換)-new在哪
栗子:子類實現接口和父類接口之間的轉換
/**
* @Author:Star
* @Date:Created in 17:18 2019/10/14
* @Description:
*/
interface IFruit{
public static final String name = "水果";//全局變量
public abstract void print();//抽象方法
}
interface IApple{
public abstract String getApple();
}
class bigAppleImpl implements IFruit,IApple{
@Override
public void print() {
System.out.println(IFruit.name);
}
@Override
public String getApple() {
return IFruit.name;
}
}
public class Test02 {
public static void main(String[] args) {
IFruit f = new bigAppleImpl();//向上轉型,爲父接口實例化對象
f.print();
IApple a = (IApple) f;
System.out.println(a.getApple());
}
}
輸出:
在上面的程序中,IFruit,IApple兩個接口可以通過它們共同的子類相互轉換;(噓...可能這個栗子不是很形象,但是基本內容已經顯示出來啦)
2.接口的使用原則
(1)接口中只允許public權限;(不管是屬性還是方法,其權限都是public)
在接口中,public、static、final、abstract均可以省掉不寫,抽象類中一個也別想跑;
規範:接口中的屬性與方法不要加任何修飾符,public也不寫,保持代碼的簡潔性;(關於這個規範,最終解釋權是:好像忘記在哪看的了,應該是阿里的編碼規約)
(2)當一個子類即需要實現接口又需要繼承抽象類時,先使用extends繼承一個抽象類,而後使用implements實現多個接口;
栗子應該是這樣的:
/**
* @Author:Star
* @Date:Created in 17:47 2019/10/14
* @Description:
*/
//接口
interface IMessage{
public void print();
}
//抽象類
abstract class News{
public abstract void getNews();
}
class MessageImpl extends News implements IMessage{
@Override
public void print() {
System.out.println("message~~~");
}
@Override
public void getNews() {
System.out.println("news~~~");
}
}
public class Test03 {
public static void main(String[] args) {
IMessage message = new MessageImpl();
message.print();
News news = (News) message;
news.getNews();
}
}
輸出:
(3)一個接口可以使用extends繼承多個接口;
再給一個栗子哦:
interface A{
void printA();
}
interface B{
void printB();
}
interface C extends A,B{
void printC();
}
class Impl implements C{
public void printA(){}
public void printB(){}
public void printC(){}
}
(4)抽象類可以使用implements實現多個接口,相反,接口無法繼承抽象類;(接口是更純粹的抽象類)
(5)接口可以定義一系列的內部結構,包括:內部普通類,內部接口;其中,使用static定義的內部接口就相當於一個外部接口;
看,這顆栗子:
interface A{
void printA();
static interface B{
void printB();//使用static定義,描述一個外部接口
}
}
3.接口的應用
(1)定義標準(USB)
(2)表示能力(行爲)(購買商品)
(3)在分佈式開發中暴露遠程服務方法
三.抽象類與接口的區別
其實,抽象類與普通類相比最大的特點是約定了子類的實現要求,但是抽象類存在單繼承侷限。如果要約定子類的實現要求並避免單繼承侷限就需要使用接口。
哈哈哈,有好多栗子啊,好餓,糖炒栗子和這個更配哦。
一起加油,一起進步(耶耶耶)