1. 程式人生 > >再看Java抽象類與介面

再看Java抽象類與介面

寫了這麼久的介面,也很少用到抽象類。

在一些原始碼中又看到,自己平時基本不會用到抽象類,但是最近學習又不記得到底有什麼區別了,再來先看一下。

首先,

java的面向物件的特徵是什麼:

面向物件程式設計有四個特徵:抽象,封裝,繼承,多型。

java墮胎的四種體現形式:

多型有四種體現形式:(JAVA多型的具體體現) 

1. 介面和介面的實現。 
2. 類和類的繼承。 
3. 過載:過載發生在同一個類中,在該類中如果存在多個同名方 
法,但是方法的引數型別個數不一樣,那麼說明該方法被重 
了。 (引數不同為過載)
4. 重寫:重寫發生在子類繼承父類的關係中,父類中的方法被子 
類繼承,方法名,返回值型別,引數完全一樣,但是方法體不 
一樣,那麼說明父類中的該方法被子類重寫了。 (只是方法體不一樣)

 

java中,一個類實現某個介面,必須重寫介面中的所有方法嗎?

不一定,關鍵要看子類是否是抽象類。
如果子類是非抽象類,則必須實現介面中的所有方法; 
如果子類是抽象類,則可以不實現介面中的所有方法,因為抽象類中允許有抽象方法的存在

介面

介面是抽象方法的集合。如果一個類實現了某個介面,那麼它就繼承了這個介面的抽象方法。這就像契約模式,如果實現了這個介面,那麼就必須確保使用這些方法。介面只是一種形式,介面自身不能做任何事情。(就像平時寫介面中的方法,必須全部實現,否則會報錯)

抽象類

在面向物件的概念中,所有的物件都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類。

抽象類除了不能例項化物件之外,類的其它功能依然存在,成員變數、成員方法和構造方法的訪問方式和普通類一樣。

(所以抽象類還是一個類的,跟介面與介面的實現不同)

由於抽象類不能例項化物件,所以抽象類必須被繼承,才能被使用。(但是一個類只能繼承一個抽象類,所以可能是這個原因所以用的比較少)

父類包含了子類集合的常見的方法,但是由於父類本身是抽象的,所以不能使用這些方法。

 

關於繼承

 java中,單繼承,也就是說 一個類最多隻能顯示地繼承於一個父類。但是一個類卻可以被多個類繼承,也就是說一個類可以擁有多個子類。

  1.子類繼承父類的成員變數

  當子類繼承了某個類之後,便可以使用父類中的成員變數,但是並不是完全繼承父類的所有成員變數。具體的原則如下:

  能夠繼承父類的public和protected成員變數不能夠繼承父類的private成員變數;(畢竟不在一個類裡面了)

  對於子類可以繼承的父類成員變數,如果在子類中出現了同名稱的成員變數,則會發生隱藏現象,即子類的成員變數會遮蔽掉父類的同名成員變數。如果要在子類中訪問父類中同名成員變數,需要使用super關鍵字來進行引用。(super關鍵字用來進行引用父類的同名成員變數)

  2.子類繼承父類的方法

  同樣地,子類也並不是完全繼承父類的所有方法。

  能夠繼承父類的public和protected成員方法;不能夠繼承父類的private成員方法;

  對於子類可以繼承的父類成員方法,如果在子類中出現了同名稱的成員方法,則稱為覆蓋,即子類的成員方法會覆蓋掉父類的同名成員方法。如果要在子類中訪問父類中同名成員方法,需要使用super關鍵字來進行引用。

  注意:隱藏和覆蓋是不同的。隱藏是針對成員變數和靜態方法的,而覆蓋是針對普通方法的。

  3.構造器

  子類是不能夠繼承父類的構造器,但是要注意的是,如果父類的構造器都是帶有引數的,則必須在子類的構造器中顯示地通過super關鍵字呼叫父類的構造器並配以適當的引數列表。如果父類有無參構造器,則在子類的構造器中用super關鍵字呼叫父類構造器不是必須的,如果沒有使用super關鍵字,系統會自動呼叫父類的無參構造器。

抽象類與介面的區別

引用網上的解答:

抽象類和介面的對比

引數 抽象類 介面
預設的方法實現 它可以有預設的方法實現 介面完全是抽象的。它根本不存在方法的實現
實現 子類使用extends關鍵字來繼承抽象類。如果子類不是抽象類的話,它需要提供抽象類中所有宣告的方法的實現。 子類使用關鍵字implements來實現介面。它需要提供介面中所有宣告的方法的實現
構造器 抽象類可以有構造器 介面不能有構造器
與正常Java類的區別 除了你不能例項化抽象類之外,它和普通Java類沒有任何區別 介面是完全不同的型別
訪問修飾符

抽象方法可以有publicprotecteddefault private

即所有的訪問控制符 (已測試)

介面方法預設修飾符是public。你不可以使用其它修飾符。
main方法 抽象方法可以有main方法並且我們可以執行它 介面沒有main方法,因此我們不能執行它。
多繼承 抽象方法可以繼承一個類和實現多個介面

介面只可以繼承一個或多個其它介面

(這裡一定要注意,是繼承!!!

也就是extends)

速度 它比介面速度要快 介面是稍微有點慢的,因為它需要時間去尋找在類中實現的方法。
新增新方法 如果你往抽象類中新增新的方法,你可以給它提供預設的實現。因此你不需要改變你現在的程式碼。 如果你往介面中新增方法,那麼你必須改變實現該介面的類。

什麼時候使用抽象類和介面

  • 如果你擁有一些方法並且想讓它們中的一些有預設實現,那麼使用抽象類吧。
  • 如果你想實現多重繼承,那麼你必須使用介面。由於Java不支援多繼承,子類不能夠繼承多個類,但可以實現多個介面。因此你就可以使用介面來解決它。
  • 如果基本功能在不斷改變,那麼就需要使用抽象類。如果不斷改變基本功能並且使用介面,那麼就需要改變所有實現了該介面的類。
  • 所以大部分基礎服務可以用抽象類
  • 比如現在公司的專案中用到的baseService BaseController等等

建立一個抽象類

public abstract class AbstractTest
{
}

也可以用 

abstract class AbstractTest
{
}//如同一個普通的類
public interface A extends  interfaceB {
//一個介面可以去竭誠另外一個介面,而且也不用非得去實現這個介面的方法
//因為介面不進行方法的實現,只是抽象出來方法
}

 介面繼承介面的意義是什麼?

public interface InterfaceA extends InterfaceB {

}

public class InterfaceAImpl implements InterfaceA {

    /**
    如果這個地方不進行重寫getCat方法的話編譯器就會提示報錯,也就是A介面繼承了B介面,
    也就把B介面的抽象方法放到了A這裡
    
    */
    @Override
    public void getCat() {
        System.out.println("I get a black cat");
    }
}

public interface InterfaceB {

    void getCat();
}

例如:java原始碼中Collection介面實現了Iterable介面,然後重新聲明瞭iterator方法。
為什麼不直接讓List同時實現Collection和Iterable介面?

一個不錯的解釋:

Interface就是使用者和實現者之間的一個合同,
比如甲承諾實現interface A裡面定義的所有公共介面,
乙承諾實現interfaceB 裡面定義的所有公共介面,
丙承諾用interfaceC 實現interfaceA 和 interfaceB 裡面所有的公共介面,也就是interface C implements InterfaceA, InterfaceB
所以甲的使用者只關心interfaceA,
乙的使用者只關心interfaceB,
丙的使用者則需要關心 interfaceA, interfaceB 和 interfaceC