這篇主要分析abstract修飾符的用法,abstract和接口的比較以及常見的面試題。
abstract詳解
abstract一般用來修飾類和方法。
1.abstract修飾類
abstract修飾類,會使得類變成抽象類,抽象類不能生成實例,但是可以作為對象變量聲明的類型,也就是編譯時類型。抽象類相當於類的半成品,需要子類繼承並覆蓋其中的方法。
注意:
- 抽象類雖然不能實例化,但是有自己的構造方法。
- 抽象類和接口(interface)有很大的不同之處,接口中不能有實例方法去實現業務邏輯,而抽象類可以有實例方法,並實現業務邏輯。
- 抽象類不能被final修飾,因為被final修飾的類無法被繼承,而對於抽象類來說就是需要通過繼承去實現抽象方法。
2.abstract修飾方法
abstract修飾方法會使得這個方法變成抽象方法,也就是只有聲明,而沒有實現,需要子類重寫。
注意:
- 有抽象方法的類一定是抽象類,但是抽象類不一定有抽象方法。
- 父類是抽象類,其中有抽象方法,那么子類繼承父類,並把父類中的所有抽象方法都實現了,子類才有創建對象實例的能力,否則子類也必須是抽象類。抽象類中可以有構造方法,子類在構造子類對象時需要調用父類(抽象類)的構造方法。
- 抽象方法不能用private修飾,因為抽象方法必須被子類重寫,而private權限對於子類來說是不能訪問的,所以就會產生矛盾。
- 抽象方法也不能用static修飾,如果用static修飾了,那么我們就可以直接通過類名調用了,而抽象方法壓根沒有主體,沒有任何業務邏輯,這樣就毫無意義了。
3.抽象類的多態性
abstract class E{
public abstract void show();// public abstract可以省略
}
然后其它類繼承它通常為了實現它里面的方法。
class F extends{
void show(){
寫具體代碼}
}
最后在主方法里定義一個父類引用指向子類對象,就會發生多態現象,比如
E e = new F();
e.show();
實際上調用了子類里面的new()方法。
4.抽象類的構造方法
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和接口的區別
1.抽象類中可以有普通成員變量,接口中沒有普通成員變量。
2.抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以是任意的,但是接口中定義的變量只是public static final類型,並且默認為public static final類型。
3.抽象類可以有構造方法,接口中不能有構造方法。
4.抽象類中可以包含靜態方法,接口中不能有靜態方法。這里注意,靜態方法不要去重寫,其次這里的靜態方法一定要有具體實現,不能是抽象的。Java8中允許接口中包含靜態方法了,可以用接口直接調用。
5.抽象類中抽象方法的訪問類型可以是public,protected,但是接口中的抽象方法只能是public類型的,並且默認為public abstract類型的。
6.一個類可以實現多個接口,但是只能繼承一個抽象類。
關於abstract的一些面試題
基本上上面的記錄都能回答這10個問題。
- 抽象類中可以有main方法。
- 可以用抽象類來實現接口,這個時候就不需要實現接口的所有方法了。
參考文章
https://blog.csdn.net/weixin_40096176/article/details/79094991
https://blog.csdn.net/f346867698/article/details/79435263
https://www.sohu.com/a/217498364_100023471