Java基礎——繼承、多態

1. 面向對象的特徵

我們都知道,java是面向對象的語言,那麼面向對象的有哪些特徵呢?

(1)抽象:將客觀事物的共性抽象出來,並將這些屬性歸爲一個類。

        包括兩個方面:過程抽象數據抽象

(2)繼承:一個新類可以從現有的類中派生。

(3)封裝:將客觀事物抽象成類,每個類對自身的數據和方法實現保護。

(4)多態:主要有兩種表現方式:方法的重載方法的覆蓋

抽象和封裝比較簡單,我們重點講解繼承和多態。

2.什麼是繼承?

通過繼承,子類可以使用父類中的一些成員變量與方法,提供代碼的複用性。

使用格式:class 子類名 extends 父類名

特性:(1)不支持多重繼承,子類至多只能有一個父類,但可以通過實現多個接口來達到多重繼承的目的(接口支持多重繼承)

(2)子類只能繼承父類的非私有(public 和 protected)成員變量和方法

(3)當子類中定義的成員變量和父類定義的成員變量同名時,子類的成員變量會覆蓋父類的成員變量,而不會繼承。

(4)當子類中的方法與父類中的方法有相同的函數簽名(相同方法名,相同參數個數和類型)時,子類將會覆蓋父類的方法,不會繼承。

3. 什麼是多態? 

它表示當同一個操作作用在不同對象時,會有不同的語義,從而產生不同的結果。

(1)方法的重載(overload):重載是指同一個類中有多個同名的方法,但是這些方法有不同的參數,因此在編譯時就可以確定到底調用哪個方法,它是一種編譯時多態

(2)方法的覆蓋 (override):子類可以覆蓋父類的方法,因此同樣的方法會在父類與子類中有着不同的表現形式。因爲父類引用不僅能指向父類對象,也能指向子類對象。所以,在執行期間(非編譯期間)需要判斷引用對象的實際類型,根據實際類型判斷並調用相應的屬性和方法。因此,也方法的覆蓋 (override)被稱爲運行時多態

運行時多態存在的三個必要條件
一、要有繼承;
二、要有重寫;
三、父類引用指向子類對象。

class Base{
	//父類的構造方法
	public Base()
	{
		g();
	}
	public void f()
	{
		System.out.println("Base f()");
	}
	public void g()
	{
		System.out.println("Base g()");
	}
}

class Derived extends Base{
	//覆蓋了父類的f()方法
	public void f()
	{
		System.out.println("Derived f()");
	}
	//覆蓋了父類的g()方法
	public void g()
	{
		System.out.println("Derived g()");
	}
}

public class Test{
	public static void main(String[] args) {
		Base b = new Derived(); //父類的引用指向了子類的實例化對象
		b.f();
		b.g();
	}
}

父類提供了無參數的構造函數,因此編譯器默認調用父類的無參數構造函數。在子類中覆蓋了父類的 f()方法和 g()方法,因此運行時實例化對象調用子類中相應的方法.

運行結果:

Derived g()

Derived f()

Derived g()

只有類中的方法纔有多態的概念,類中的成員變量沒有多態的概念。 

成員變量的值並不取決於創建對象的類型,而是取決於所定義變量的類型

class Base{
	public int i =1;
}

class Derived extends Base{
	public int i = 2;
}

public class Test {
    public static void main(String[] args) {
		Base b = new Derived();   //變量類型爲Base
		System.out.println(b.i);
	}
}

輸出結果:1

i 的值並不取決於創建對象的類型,而取決於定義變量的類型。變量b的類型爲Base ,所以輸出爲1,這是在編譯時就能確定的,也不具備多態性。

Base b = new Derived(); 改爲Derived b = new Derived();則輸出爲2

 

總結:

重載的注意點:

(1)重載是通過不同的方法參數來區分的,例如不同的參數個數、不同的參數類型、不同的參數順序。不能通過方法的訪問權限、返回值類型和拋出的異常類型來進行重載。

(2)對於繼承來說,如果父類方法的訪問權限爲private,那麼不能在子類中對其重載。如果在子類中也定義了一個同名的函數,這只是一個新的方法,不會達到重載的效果。(繼承只能繼承父類的非私有成員)

覆蓋的注意點:

(1)子類中的覆蓋方法必須和父類中被覆蓋方法有相同的函數名、參數、返回值。

(2)子類的覆蓋方法所拋出的異常必須和父類被覆蓋的方法所拋出的異常一致。

(3)父類中被覆蓋的方法不能爲private,否則其子類只是定義了一個方法,並沒有對其覆蓋。

4.重載和覆蓋的區別

 (1)覆蓋是子類和父類之間的關係,是垂直的關係;重載是同一個類中方法之間的關係,是水平關係。

(2)覆蓋要求參數列表相同;重載要求參數列表不同

(3)覆蓋關係中,調用方法體是根據對象的類型來決定的,而重載關係是根據調用時的實參數表與形參數表來選擇方法體的。

如下代碼的運行結果是什麼? 

答案:編譯報錯。因爲函數是不能以返回值來區分的,雖然父類與子類中的函數有着不同的返回值,但它們有着相同的方法簽名,因此,編譯器無法區分。


class Super{
	public int f()
	{
		return 1;
	}
}

public class SubClass extends Super{
	public float f()                //這裏會報錯
	{
		return 2f;
	}
	public static void main(String[] args) {
		Super s = new SubClass();
	    System.out.println(s.f());
	}
}

 

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