JAVA基礎之三-介面和抽象類

正在战斗中發表於2024-08-31

java提供了抽象類和介面,總體是好事。

有的OOP語言並沒有介面的概念,但相當一部分其實用其它方式實現了JAVA中介面類似的功能。

如果不太清楚二者的區別,難免在面臨具體業務的時候,在二者之間搖擺。

---

實際上,關於抽象類和介面的共同點和不同點沒有什麼可以寫的。

設計原則原則讓我們儘量基於介面程式設計(IOP-Interface-Oriented Programming),而不是基於具體類,所以多用介面。

如果需要繼承(通常就存在屬性),則多用抽象類。

---

一、基本概念

這裡有個難點:java的抽象類和介面已經不如發明者期望的那麼純粹了。

所以,以下的概念主要適用於J17及其以上版本。

2.1、抽象類

核心概念:無法例項化的類

用處:為子類提供模板,限定子類的實現,併為子類提供一些公共的且已經實現的方法/屬性。

可以包含內容:各種可見範圍的都可以,最典型的就是抽象方法。除了不能用default,好像就麼有不行的。

如果只定義了抽象方法,那麼它的作用基本等同於介面。

2.2、介面

核心概念:必須被實現的類,否則無用(但實際不是那麼回事,自從J9之後可以工具化)

用處:抽象以實現工程上的多型,從而實現模組話;為函數語言程式設計服務

可以包含內容:除了不能定義只包含public修飾符的方法,好像都可以。

二、比較

總體來說,java的抽象類和介面越發地同化了,除了以下幾個不能互相替代,好像沒有不能互換的:

a.抽象類的可以實現各種修飾符的方法或者屬性 -- 介面做不到,至少介面不能定義只有public修飾符的方法

b.介面可以用於實現函數語言程式設計;介面可以用於實現註解

抽象類更適合於定義帶有屬性的類,介面更適合用於只有實現方法的類(雖然可以帶靜態屬性)。

因為介面的這個特性,所以,介面很適合用於定義spring中bean,因為我們用bean的最主要目的就是為了實現單例的bean,

我們通常不關注特定的bean示例到底有什麼特性,只像知道某個bean示例能幹什麼。

所以,java這種和spring結合很深的語言,介面有大用處。

當然,在spring中,如果bean繼承抽象類來是實現bean的定義和注入也是可以的,不過這個時候,就不要為抽象類定義什麼屬性了。

以下就是這個演示(已經省略了包和import部分):

package study.base.oop.classes.modifier.abstractbean;

/**
 * 抽象類,用於演示基於抽象類的 bean
 */
public abstract class AbstractLiterature {
    
    public abstract String writePoem();
}
 
@Component
public class ChineseLiteratureService extends AbstractLiterature {

    @Override
    public String writePoem() {
        return """
                兩個黃鸝鳴翠柳,
                一行白鷺上青天。
                醉裡挑燈看劍,夢迴吹角連營.八百里分麾下炙人,五十先翻塞外聲,沙場秋點兵。                            
                """;
    }

}

@RequestMapping("/spring/bean/")
@Controller
public class BeanController {

    @Autowired
    private AbstractLiterature literatureService;
    
    @GetMapping("/abstract-bean")
    @ResponseBody
    public Object testAbstractBean() {
        String poem= this.literatureService.writePoem();
        return poem;
    }    
}

編譯不會報錯,結果也可以看到:

所以,用介面還是用抽象類來介面定義,真是一個問題。

三、適用場景

3.1 想想要不要個性化的屬性

如前,如果想保留自有屬性,那麼用抽象類更好一些;如果不需要保留自有屬性,用介面更好一些。

實現一個bean的時候為什麼都是基本是實現一個介面,而不是擴充套件一個抽象類?

也許僅僅處於兩個考慮:

1.即使偏好抽象類,也需要避免有人往抽象類中新增屬性,變成不穩定的bean

2.僅僅基於一個樸素的想法:單例bean還要什麼屬性,所以用理論山乾淨一點的介面更好一些。

因為第2個因素的緣故,所以我們都會再三強調,不要在bean中定義可變的屬性/成員,即使要定義了,我們也是為了用這些

成員的能力而不是成員的資料。這樣做的最重要的目的是為了保證獲得方法的某種程度的冪等性。

一旦實現類的屬性(作為資料)參與方法計算,那麼由於單例的特性,可能會照成難於預料的結果,通常那不是我們期望

的結果。

為什麼單例bean的屬性會被共享? 這和JVM的記憶體模型有不可分割的關係。

3.2 介面特有的

至於註解和函數語言程式設計,現在只能求助於介面。

如果要實現多繼承,現在也只能求助於介面。

3.3預設使用介面的

具體到JAVA的經典應用場景-開發資訊應用系統後臺,那麼還是偏多使用介面。這是因為現在javaEE基本和Spring深度繫結,

spring和Bean深度繫結,Bean基本上就是單例bean,單例意味著不要特性化的屬性,不要屬性,那麼用介面無疑是最好不過了。

3.4 不用bean的地方-也許抽象類可以排上用場

當我們不用bean的時候,通常意味著要寫一些相對複雜一些的功能,這個時候抽象類可能更加方便一些。

如果需要定義公共的描述,並基於這個定義構建大模組,可以考慮用抽象類,或者普通的類也可以。

四、小結

雖然隨著JAVA版本的變更,介面和抽象類越發相像。

讓介面專享註解和函數語言程式設計,使得介面顯得有點獨大。

不過當你不想單例的時候,應該更多考慮抽象類。

相關文章