解析JavaSe的抽象類和接口
1. 抽象類和抽象方法
抽象方法和抽象類必須使用abstract修飾符來定義,有抽象方法的類只能被定義成抽象類,抽象類里可以沒有抽象方法。抽象方法和抽象類的規(guī)則如下:
(1) 抽象類和抽象方法必須使用abstract修飾符來修飾,抽象方法不能有方法體。
(2) 抽象類不能被實例化,無法使用new關(guān)鍵字來調(diào)用抽象類的構(gòu)造器創(chuàng)建抽象類的實例。即使抽象類里不包含抽象方法,這個抽象類也不能創(chuàng)建實例。
(3) 抽象類可以包含F(xiàn)ield、方法、構(gòu)造器、初始化塊、內(nèi)部類、枚舉類6種成分。抽象類的構(gòu)造器不能用于創(chuàng)建實例,主要是用于被其子類調(diào)用。
(4) 含有抽象方法的類只能被定義成抽象類。
(5) abstract不能用于修飾Field,不能用于修飾局部變量,即沒有抽象變量、沒有抽象Field等說法;abstract也不能用于修飾構(gòu)造器,沒有抽象構(gòu)造器,抽象類里定義的構(gòu)造器只能是普通構(gòu)造器。
定義抽象方法只需在普通方法上增加abstract修飾符,并把普通方法的方法體(也就是方法后花括號括起來的部分)全部去掉,并在方法后增加分號即可。
public abstract class Person { // 初始化塊 { System.out.println("執(zhí)行Person類的初始化塊"); } private int age; // 該構(gòu)造器并不是為了創(chuàng)建對象,而是為了子類調(diào)用 public Person(){ } public Person(int age){ this.age = age; } // 抽象方法,沒有方法體 public abstract void show(); public void test(){ System.out.println("非抽象方法"); } }
抽象類不能用于創(chuàng)建實例,只能當(dāng)作父類被其他子類繼承。
public class Student extends Person { public Student(int age){ super(age); } @Override public void show() { System.out.println("重寫抽象類中的抽象方法"); } }
注意:
(1) 當(dāng)使用abstract修飾類時,表明這個類只能被繼承;當(dāng)使用abstract修飾方法時,表明這個方法必須由子類提供實現(xiàn)(即重寫)。而final修飾的類不能被繼承,final修飾的方法不能被重寫。因此final和abstract永遠(yuǎn)不能同時使用。
(2) 當(dāng)使用static修飾一個方法時,表明這個方法屬于該類本身,即通過類就可調(diào)用該方法,但如果該方法被定義成抽象方法,則將導(dǎo)致通過該類來調(diào)用該方法時出現(xiàn)錯誤(調(diào)用了一個沒有方法體的方法肯定會引起錯誤)。因此static和abstract不能同時修飾某個方法,即沒有所謂的類抽象方法。
(3) 抽象類不能創(chuàng)建實例,只能當(dāng)成父類來被繼承。從語義的角度來看,抽象類是從多個具體類中抽象出來的父類,它具有更高層次的抽象。
2. 相關(guān)面試題
1、抽象類必須要有抽象方法嗎?
抽象類不一定非要有抽象方法,抽象類中可以含有抽象方法和非抽象方法,可以只含有抽象方法,也可以只含有非抽象方法
public abstract class Person { public void test(){ System.out.println("非抽象方法"); } }
2、普通類和抽象類有哪些區(qū)別?
(1) 普通類不能包含抽象方法,抽象類可以包含抽象方法。
(2) 抽象類不能直接實例化,只能當(dāng)作父類被其他子類繼承,普通類可以直接實例化。
public abstract class Person { // 抽象方法 public abstract void show(); // 非抽象方法 public void test(){ System.out.println("非抽象方法"); } }
外部類的形式繼承抽象類Person
public class Student extends Person { @Override public void show() { System.out.println("重寫抽象類中的抽象方法"); } }
內(nèi)部類的形式繼承抽象類Person
public class Teacher { public static void main(String[] args) { Person person = new Person() { @Override public void show() { System.out.println("重寫抽象類的抽象方法"); } }; person.show(); } }
3、抽象類能使用 final 修飾嗎?
當(dāng)使用abstract修飾類時,表明這個類只能被繼承;當(dāng)使用abstract修飾方法時,表明這個方法必須由子類提供實現(xiàn)(即重寫)。而final修飾的類不能被繼承,final修飾的方法不能被重寫。因此final和abstract永遠(yuǎn)不能同時使用。
3. 接口
接口只是對一類事物的屬性和行為更高層次的抽象。對修改關(guān)閉,對擴展(不同的實現(xiàn)implements)開放,接口是對開閉原則的一種體現(xiàn)。
接口體:
interface 接口名{ 常量 抽象方法 靜態(tài)方法 默認(rèn)方法}interface 接口名 { 常量 抽象方法 靜態(tài)方法 默認(rèn)方法 }
3.1 接口中的常量
接口中的所有成員變量都默認(rèn)是由public static final修飾的,且由于接口里沒有構(gòu)造器和初始化塊,因此需要在定義Field時就指定初始值;
接口中的Field都是常量,經(jīng)常用來被定義常量的集合:
public interface FieldInterface { /** * 一年的天數(shù) */ int DAY = 365; /** * 一年的星期數(shù) */ int WEEK = 52; /** * 一年的月數(shù) */ int MONTH = 12; }
public class Main { public static void main(String[] args) { /** * 接口中定義的Field都是public static final修飾的常量,因此需要使用接口名來訪問 */ System.out.println(FieldInterface.DAY); } }
一個類實現(xiàn)某個接口時,該類將會獲得接口中定義的Field :
public class FieldImpl implements FieldInterface { // 將會繼承FieldInterface中定義的所有Field }
public class Main { public static void main(String[] args) { System.out.println(FieldInterface.DAY); // 使用實現(xiàn)類調(diào)用接口中的常量 System.out.println(FieldImpl.DAY); } }
3.2 接口中的方法
接口中的三種方法:
(1) 接口中的普通方法,默認(rèn)都是public abstract修飾的抽象方法,沒有方法體;
(2) 接口中的靜態(tài)方法,靜態(tài)方法必須要有實現(xiàn),且這個靜態(tài)方法只能用public修飾或不寫;
(3) 接口中的默認(rèn)方法,默認(rèn)方法必須要有實現(xiàn),用default修飾且不可省略,用來供子類繼承或重寫,二選一,但只能在實現(xiàn)類中使用或者實現(xiàn)類對象中使用;
分別展開舉例說明:
3.2.1 接口中的普通方法
接口中的普通方法,默認(rèn)都是public abstract修飾的抽象方法,沒有方法體;
- 接口的實現(xiàn)類如果是普通類,那么必須重寫接口中的所有抽象方法
- 接口的實現(xiàn)類如果是抽象類,那么可以不用重寫接口中的抽象方法
public interface BaseMethod { /** * 接口中的普通方法 * 以下方法默認(rèn)都是public abstract修飾的抽象方法,沒有方法體 */ public abstract void show1(); abstract void show2(); public void show3(); void show4(); }
① 接口的實現(xiàn)類如果是普通類,那么必須重寫接口中的所有抽象方法:
public class BaseMethodImpl implements BaseMethod { /** * 當(dāng)一個類實現(xiàn)BaseMethod接口后,需要實現(xiàn)BaseMethod接口中的所有抽象方法 */ @Override public void show1() { } @Override public void show2() { } @Override public void show3() { } @Override public void show4() { } }
② 接口的實現(xiàn)類如果是抽象類,那么可以不用重寫接口中的抽象方法:
public abstract class BaseMethodImpl2 implements BaseMethod { /** * 抽象類會繼承接口中定義的所有抽象方法和field * 這個類仍然是抽象類,可以不用實現(xiàn)接口中所有的抽象方法 */ @Override public void show1() { } }
3.2.2 接口中的靜態(tài)方法
- 調(diào)用形式:接口名.靜態(tài)方法名
- 接口中定義的靜態(tài)方法,不能被子接口繼承
- 接口中定義的靜態(tài)方法,不能被實現(xiàn)該接口的類繼承
public interface StaticMethod { /** * 接口中的靜態(tài)方法 * 接口中是可以定義靜態(tài)方法的,靜態(tài)方法必須要有實現(xiàn)。且這個靜態(tài)方法只能用public修飾或不寫。 */ public static void test1(){ System.out.println("接口中定義靜態(tài)方法"); } }
public class Main { public static void main(String[] args) { /** * 接口中的靜態(tài)方法,只能通過接口名來調(diào)用,就像類的靜態(tài)方法一樣 */ StaticMethod.test1(); } }
① 接口中定義的靜態(tài)方法不能被子接口繼承:
public interface StaticMethod1 extends StaticMethod { }
public class Main { public static void main(String[] args) { /** * 編譯報錯,說明接口中定義的靜態(tài)方法不能被子接口繼承 */ StaticMethod1.test1(); } }
② 接口中定義的靜態(tài)方法不能被實現(xiàn)類繼承:
public class StaticMethodImpl implements StaticMethod { }
public class Main { public static void main(String[] args) { /** * 編譯報錯,說明接口中定義的靜態(tài)方法不能被實現(xiàn)類繼承 */ StaticMethodImpl.test1(); } }
3.2.3 接口中的默認(rèn)方法
- 接口中的默認(rèn)方法,不能通過接口名調(diào)用,需要通過接口實現(xiàn)類的實例進行訪問,即對象名.默認(rèn)方法名()
- 接口中的默認(rèn)方法,可以被實現(xiàn)類繼承,也可以在實現(xiàn)類中重寫
- 接口中的默認(rèn)方法,可以被子接口繼承,也可以在子接口中重寫
public interface DefaultMethod { /** * 接口中的默認(rèn)方法 * 用default修飾,不可省略,供子類繼承或重寫,二選一,但只能在實現(xiàn)類中使用或者實現(xiàn)類對象中使用 */ public default void test2(){ System.out.println("接口中定義默認(rèn)方法"); } }
① 接口中的默認(rèn)方法,可以被實現(xiàn)類繼承,也可以在實現(xiàn)類中重寫
public class DefaultMethodImpl implements DefaultMethod { // 繼承接口中的方法 }
public class DefaultMethodImpl implements DefaultMethod { // 重寫接口中的方法 @Override public void test2() { System.out.println("實現(xiàn)類重寫接口中的方法"); } }
public class DefaultMethodImpl implements DefaultMethod { // 重寫接口中的方法 @Override public void test2() { System.out.println("實現(xiàn)類重寫接口中的方法"); } }
② 接口中的默認(rèn)方法,可以被子接口繼承,也可以在子接口中重寫
public interface DefaultMethod1 extends DefaultMethod { // 繼承父接口中的方法 }
public interface DefaultMethod1 extends DefaultMethod { // 重寫父接口中的方法 @Override default void test2() { System.out.println("子接口中重寫父接口中的方法"); } }
3.3 接口中的接口和枚舉類
public interface Base { /** * 在接口中定義接口 */ interface CommonConstant{ /** * 一年的天數(shù) */ int DAY = 365; /** * 一年的星期數(shù) */ int WEEK = 52; /** * 一年的月數(shù) */ int MONTH = 12; /** * 在接口中定義靜態(tài)方法 */ static void show() { System.out.println("在接口中定義接口"); } } /** * 在接口中定義枚舉類 */ @AllArgsConstructor enum WhiteStatusEnum { /** * 未加白 */ NO_WHITE("未加白", "未加白"), /** * 部分加白 */ PART_WHITE("部分加白", "部分加白"), /** * 全部加白 */ ALL_WHITE("全部加白", "全部加白"); @Getter private final String label; @Getter private final String value; } }
3.4 接口和抽象類
共同點:
(1) 接口和抽象類都不能被實例化,它們都位于繼承樹的頂端,用于被其他類實現(xiàn)和繼承;
(2) 接口和抽象類都可以包含抽象方法,實現(xiàn)接口或繼承抽象類的普通子類都必須實現(xiàn)這些抽象方法;
(3) 接口和抽象類中都可以包括抽象方法和非抽象方法;
不同點:
(1) 接口里只能定義靜態(tài)常量Field,不能定義普通Field;抽象類里則既可以定義普通Field,也可以定義靜態(tài)常量Field。
(2) 接口里不包含構(gòu)造器;抽象類里可以包含構(gòu)造器,抽象類里的構(gòu)造器并不是用于創(chuàng)建對象,而是讓其子類調(diào)用這些構(gòu)造器來完成屬于抽象類的初始化操作。
(3) 接口里不能包含初始化塊;但抽象類則完全可以包含初始化塊。
(4) 一個類最多只能有一個直接父類,包括抽象類;但一個類可以直接實現(xiàn)多個接口,通過實現(xiàn)多個接口可以彌補Java單繼承的不足。
public class MethodImpl implements FieldInterface, MethodInterface { }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringCloud Feign遠(yuǎn)程調(diào)用實現(xiàn)詳解
Feign是Netflix公司開發(fā)的一個聲明式的REST調(diào)用客戶端; Ribbon負(fù)載均衡、 Hystrⅸ服務(wù)熔斷是我們Spring Cloud中進行微服務(wù)開發(fā)非?;A(chǔ)的組件,在使用的過程中我們也發(fā)現(xiàn)它們一般都是同時出現(xiàn)的,而且配置也都非常相似2022-11-11Java實現(xiàn)PDF轉(zhuǎn)為Word文檔的示例代碼
眾所周知,PDF文檔除了具有較強穩(wěn)定性和兼容性外,?還具有較強的安全性,在工作中可以有效避免別人無意中對文檔內(nèi)容進行修改。本文將分為以下兩部分介紹如何在保持布局的情況下將PDF轉(zhuǎn)為Word文檔,希望對大家有所幫助2023-01-01使用Spring Cloud Feign遠(yuǎn)程調(diào)用的方法示例
這篇文章主要介紹了使用Spring Cloud Feign遠(yuǎn)程調(diào)用的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09Unity&Springboot實現(xiàn)本地登陸驗證
本文主要介紹了Unity&Springboot服務(wù)器/本地登陸驗證,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07SpringBoot+Mybatis plus實現(xiàn)多數(shù)據(jù)源整合的實踐
本文主要介紹了SpringBoot+Mybatis plus實現(xiàn)多數(shù)據(jù)源整合的實踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10