Java面向對象特性之二繼承

繼承的好處

1.提高代碼的複用性
2.繼承讓類與類之間產生了關係,有了這個關係,纔有了多態的特性。
JAVA語言,只支持單繼承,不支持多繼承(接口之間可以多繼承,因爲都抽象,沒有方法體就不衝突),因爲多繼承容易帶來安全隱患。但是支持多層繼承。(爺爺-爸爸-孫子)

繼承的弊端

打破了封裝性。

繼承的特點

父子類出現以後,類成員特點:

  1. 變量
    如果子類中出現非私有的同名成員變量時,子類要訪問本類中的變量,用this
    子類要訪問父類中同名變量時,用super

    this代表本類對象的引用
    super代表父類對象的引用
    當父類中定義了變量,子類就不用再定義了。
    如果子父類中的方法相同,子類調用方法,會調用子類的方法 這叫覆蓋(重寫)

  2. 函數
    當子類出現和父類一模一樣的函數時,當子類對象調用該函數時,會運行子類函數的內容,
    如同父類的函數被覆蓋一樣,這種情況是函數的另外一個特性:重寫(覆蓋)

    當子類繼承了父類,沿襲了父類的功能,到子類中,但是子類雖具有該功能,但是功能的內容卻和父類不一致,這時,沒有必要定義新功能,而是使用覆蓋特殊,保留父類的功能定義,並重寫功能內容。

覆蓋注意:
子類覆蓋父類,必須保證子類權限要大於等於父類權限,纔可以覆蓋,否則編譯失敗(public private protect)
靜態只能覆蓋靜態,靜態不能覆蓋非靜態。

重載:只看同名函數的參數列表
重寫:子父類方法要一模一樣。

  1. 構造函數
    在對子類對象初始化時,父類構造函數也會運行,那是因爲子類的構造函數默認第一行有一條隱式的語句 super();
    super();會訪問父類中空參數的構造函數,而且子類中所有的構造函數默認第一行都是super();
    在這裏插入圖片描述
    :爲什麼子類一定會調用父類的構造函數?
    :因爲父類中的數據,子類可以直接獲取,所以子類對象在建立時,需要先查看父類是如何對這些數據進行初始化的,所以,子類在對象初始化時,要先訪問父類中的構造函數
    如果要通過訪問父類中指定的構造函數,可以通過手動定義super來指定構造函數。當父類中構造函數定義了有參數的比如Fu(int x){xxx},子類就不能用隱式訪問的語句而是通過super(4);這樣指定父類的構造方法。

super語句一定要放在構造函數的第一行,通常定義子類構造函數的第一行,

所以,當子類的第一行寫了this();則構造函數裏沒有隱式的super()
構造函數裏要麼有this 要麼有super 因爲他倆都只能放第一行(爲什麼this和super要在第一行,因爲初始化動作要先做)。

子類實例化過程:
子類的所有的構造函數,默認都會訪問父類中空參數的構造函數
因爲子類每一個構造函數內的第一行都有一句隱式super()
當父類中沒有空參數的構造函數時,子類必須手動通過super 語句形式來制定訪問父類中的構造函數

當然,子類的構造函數第一行,也可以手動指定this語句來訪問本類中的構造函數,子類中至少有一個構造函數會訪問父類的構造函數即可。

final關鍵字

final:最終
1. 作爲一個修飾符,可以修飾類、變量、函數。
2. 被final修飾的類不可以被繼承(爲了避免被繼承,被子類複寫功能)
3. 被final修飾的方法不可以被複寫
4. 被final修飾的變量是一個常量,只能賦值一次,既可以修飾成員變量,又可以修飾局部變量。 當在描述事物時,一些數值的出現值是固定的,那麼這時爲了增強閱讀性,都給這些值起個名字。方便閱讀,而這個值不需要改變,所以加上final修飾,作爲常量,
5. 內部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量
比如:public static final double PI =3.14

abstract 關鍵字

abstract:抽象
當多個類中出現了相同功能,但是功能主體不同(學生(小學、中學、大學)學習內容不同),這時也可以進行向上抽取,只抽取功能定義,不抽取功能主體。
abstract 抽象(看不懂的方法)方法沒有主體,抽象方法必須也放在抽象的類裏。

  • 抽象類的特點

    1. 抽象方法一定定義在抽象類中,
    2. 抽象方法和抽象類都必須被abstract關鍵字修飾
    3. 抽象類不可以用new創建對象,因爲調用抽象方法沒有意義
    4. 抽象類中的抽象方法要被使用,必須由子類複寫起所有的抽象方法後,建立子類對象調用
      注意: 如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類。當然,也可以在抽象類中定義不抽象的方法(其實是爲了不讓該類建立對象。),抽象類不可以實例化。
  • 抽象的好處:
    強制子類去複寫。建立自己的特有內容。

小例子

需求:獲取一段程序運行的時間
原理:獲取程序開始和結束的時間並相減即可
獲取時間的方法:System.currentTimeMillis();

getTime()方法是獲取時間類的核心方法,不希望被重寫,加final修飾
runCode()因爲要執行的程序不確定,父類則只定義方法,沒有功能主體。將其暴露出去,讓子類實現。

abstract class GetTime{
	
	public final void getTime() {
		long start = System.currentTimeMillis();
		runCode();//要執行的程序

		long end = System.currentTimeMillis();
		System.out.println("");
		System.out.println("毫秒:"+(end-start));
	}
	public abstract void runCode();
}
class SubTime extends GetTime{
	public void runCode() {
		for(int x = 0; x<4000; x++) {
			System.out.print(x);
		}
	}
}

public class TemplateDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SubTime st = new SubTime();
		st.getTime();

	}

}

這種方式:模板方法設計模式
在定義功能時,功能的一部分是確定的,有一部分是確定的,確定的部分在使用不確定的部分,這時,就將不確定的部分暴露出去。讓子類去實現。(當然這個抽象與否要具體分析,如果有默認實現可以不抽象。)

interface關鍵字

interface:接口
初期理解,可以認爲是一個特殊的抽象類。當抽象類中的方法都是抽象的,該類可以通過接口的形式來表示。所以,接口是不可以創建對象的,因爲有抽象方法。接口需要被子類實現,子類對接口中的抽象方法全部覆蓋後,子類纔可以實例化。否則子類是一個抽象類。

class用於定義類
interfase 用於定義接口

接口定義:常量、抽象方法,有固定的修飾符,不寫也會自動補,
常量:public static final
方法:public abstract
接口中份的成員都是public
如:

interface Inter{
    //public static final int NUM = 3;
    //public abstract void show();
    int NUM = 3;
    void show();
}
  • 接口的特點:
  1. 接口是對外暴露的規則
  2. 接口是程序的功能擴展
  3. 接口可以用來多實現
  4. 類與接口之間是實現關係,而且類可以繼承一個類的同時實現多個接口
  5. 接口與接口之間可以有繼承關係

接口與接口之間也有關係 可以有繼承關係,接口之間可以多繼承(因爲都抽象,沒有方法體就不衝突)。接口的出現降低了藕合性,模塊化開發。

一個類在繼承一個類的同時,還可以去實現多個接口。
如:
class Test extends Demo implements Inter,Inter1{}

繼承和接口的區別

接口可以被類多實現,也是對多繼承不支持的一種轉換形式(多繼承不支持的原因:父類方法有重複,子類調用會有問題,多繼承有方法體)。接口沒有這個問題,因爲多繼承沒有方法體,可以由子類任意定義。

繼承是 is a 所屬 -》你是我其中一種
接口是 (體系以外的功能擴展),like a 你像我中的一個。
由後期具體對象去實現,

基本功能用繼承,擴展功能用接口
什麼是基本功能,什麼是擴展功能。都取決於組織。
比如:
運動員:
運動時基本功能(打籃球、踢足球、打排球、打乒乓球…)
學習是擴展功能(學英語)
學生:
學習是基本功能(學英語、學法語、學日語…)
運動時擴展功能(打籃球)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章