本篇文章主要分析abstract修飾符的用法,abstract和接口的比較以及常見的面試題。
文章部分內容來源於網絡,轉載請標明出處,並標記作者ID:Soinice
abstract 簡介
字面意思抽象,abstract一般用來修飾類和方法。
抽象就是把一個對象分析出各個屬性, 來替代表達的手法 。
抽 就是抽離;象 ,表象。表示出來的部分。
簡單地說:“抽象只從正確的角度,透露對象的某些相關細節。”
在面向對象編程理論中,抽象涉及到定義抽象對象的語言基礎,它到底如何工作、如何獲取和改變狀態,並與系統中的其他對象進行“交流”。
抽象在任何編程語言中的許多方面起作用。從創建子程序到定義接口來,生成低級語言調用,例如設計模式。
在《Java編程思想》第9章 接口中 有這麼一段話:
“爲此,Java提供了一種叫抽象方法的機制,這種方法是不完整的,僅有聲明而沒有方法體。
包含抽象方法的類叫做抽象類。如果一個類包含一個或多個抽象方法,該類必須限定爲抽象的。(否則,編譯器會報錯)”
abstract 用法
修飾方法
abstract修飾方法會使得這個方法變成抽象方法,也就是隻有聲明,而沒有實現,需要子類重寫。
注意:
- 有抽象方法的類一定是抽象類,但是抽象類不一定有抽象方法。
- 父類是抽象類,其中有抽象方法,那麼子類繼承父類,並把父類中的所有抽象方法都實現了,子類纔有創建對象實例的能力,否則子類也必須是抽象類。抽象類中可以有構造方法,子類在構造子類對象時需要調用父類(抽象類)的構造方法。
- 抽象方法不能用private修飾,因爲抽象方法必須被子類重寫,而private權限對於子類來說是不能訪問的,所以就會產生矛盾。
- 抽象方法也不能用static修飾,如果用static修飾了,那麼我們就可以直接通過類名調用了,而抽象方法壓根沒有主體,沒有任何業務邏輯,這樣就毫無意義了。
修飾類
abstract修飾類,會使得類變成抽象類,抽象類不能生成實例,但是可以作爲對象變量聲明的類型,也就是編譯時類型。抽象類相當於類的半成品,需要子類繼承並覆蓋其中的方法。
注意:
- 抽象類雖然不能實例化,但是有自己的構造方法。
- 抽象類和接口(interface)有很大的不同之處,接口中不能有實例方法去實現業務邏輯,而抽象類可以有實例方法,並實現業務邏輯。
- 抽象類不能被final修飾,因爲被final修飾的類無法被繼承,而對於抽象類來說就是需要通過繼承去實現抽象方法。
抽象類的多態性
abstract class E{
// public abstract可以省略
public abstract void show();
}
然後其它類繼承它通常爲了實現它裏面的方法。
class F extends{
void show(){
寫具體代碼
}
}
最後在主方法裏定義一個父類引用指向子類對象,就會發生多態現象,比如
E e = new F();
e.show();
實際上調用了子類裏面的new()方法。
抽象類的構造方法
public abstract class Car {
Car(){
System.out.println("抽象方法無參構造函數");
}
Car(String a){
System.out.println("抽象有參構造方法");
}
public void mothod1(){
System.out.println(this.getClass());
System.out.println("抽象類的實例方法");
}
public abstract void mothod2();
}
/**
* 自行車
*/
class Bicycle extends Car{
Bicycle(){
System.out.println("子類無參構造函數");
}
@Override
public void mothod2() {
//需要覆寫抽象方法mothod2
}
}
/**另一個包的測試類**/
public class Test {
public static void main(String[] args) {
Bicycle b = new Bicycle();
b.mothod1();
}
}
輸出:
抽象方法無參構造函數
子類無參構造函數
class com.shaolin.service.impl.Bicycle
抽象類的實例方法
從上面的例子中可以看出:
-
抽象類是有構造方法的(當然如果我們不寫,編譯器會自動默認一個無參構造方法)。而且從結果來看,和普通的繼承類一樣,在new 一個子類對象時會優先調用父類(這裏指的是抽象類Car)的構造器初始化,然後再調用子類的構造器。至此相信大家都會有這樣一個疑問,爲什麼抽象方法不能實例化卻有構造器呢? 對於這個問題網上也中說紛紜,沒有確定答案。
我是這樣想的:既然它也屬於繼承的範疇,那麼當子類創建對象時必然要優先初始化父類的屬性變量和實例方法,不然子類怎麼繼承和調用呢?而它本身不能實例化,因爲它本身就是不確定的一個對象,如果它能被實例化,那麼我們通過它的對象來調用它本身的抽象方法是不是有問題。所以不能實例化有在情理之中。因此大家只要記住這個規定就行。 -
對於抽象類中的非statci(靜態)和非abstract(抽象)方法中的this關鍵字(靜態方法中不能有關鍵字this,因爲static方法可以直接由類名調用,this指代對象,沒有實例化就沒有對象,所以在static方法中不使用this)代表的是它的繼承類,而非抽象類本身,這個好理解,因爲抽象類本身不能被實例化。如果有多個繼承類,誰調用this就代表誰。
abstract 和接口的區別
- 抽象類中可以有普通成員變量,接口中沒有普通成員變量。
- 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以是任意的,但是接口中定義的變量只是public static final類型,並且默認爲public static final類型。
- 抽象類可以有構造方法,接口中不能有構造方法。
- 抽象類中可以包含靜態方法,接口中不能有靜態方法。這裏注意,靜態方法不要去重寫,其次這裏的靜態方法一定要有具體實現,不能是抽象的。Java8中允許接口中包含靜態方法了,可以用接口直接調用。
- 抽象類中抽象方法的訪問類型可以是public,protected,但是接口中的抽象方法只能是public類型的,並且默認爲public abstract類型的。
- 一個類可以實現多個接口,但是隻能繼承一個抽象類。
關於abstract的一些面試題
基本上上面的記錄都能回答這10個問題。
-
抽象類中可以有main方法。
- 可以用抽象類來實現接口,這個時候就不需要實現接口的所有方法了。
總結
抽象類有什麼好處呢?
-
由於抽象類不能被實例化,最大的好處就是通過方法的覆蓋來實現多態的屬性。也就是運行期綁定
- 抽象類將事物的共性的東西提取出來,由子類繼承去實現,代碼易擴展、易維護。