——繼承與多態

---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity開發</a>、<a href="http://www.itheima.com"target="blank">.Net培訓</a>、期待與您交流! ----------------------

繼承

繼承是面對對象的三大特徵之一,也是實現多態的方式之一。

一個類繼承另一個類的時候,可以繼承除了構造函數以外的所有類成員。

繼承的優缺點:

繼承的優點:
      1,提高了代碼的複用性。
      2,讓類與類之間產生了關係。有了這個關係,纔有了多態的特性。

繼承的缺點:打破了封裝性。

繼承的語法:

java中繼承用的extends關鍵字

如:

class A extends B{

}

注:千萬不要爲了獲取其他類的功能,簡化代碼而繼承。
必須是類與類之間有所屬關係纔可以繼承。所屬關係 is a。

--------------------------------------------------------------------------------

繼承的規則:

Java語言中:java只支持單繼承,不支持多繼承。

因爲多繼承容易帶來安全隱患:當多個父類中定義了相同功能,

當功能內容不同時,子類對象不確定要運行哪一個。

但是java保留這種機制。並用另一種體現形式來完成表示。多實現。

java支持多層繼承。也就是一個繼承體系。



繼承中功能的使用:

想要使用體系,先查閱體系父類的描述,因爲父類中定義的是該體系中共性功能。
通過了解共性功能,就可以知道該體系的基本功能。
那麼這個體系已經可以基本使用了。
那麼在具體調用時,要創建最子類的對象,爲什麼呢?
一是因爲有可能父類不能創建對象,
二是創建子類對象可以使用更多的功能,包括基本的也包括特有的。

簡而言之:查閱父類功能,創建子類對象使用功能。

示例代碼:

package com.itheima.base;
/**
 * 繼承
 * @author wuyong
 *
 */
public class ExtendsDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Father father1 = new Father();
		father1.show();
		Sun sun = new Sun();
		sun.show();
	}

}
/**
 * 父類Father
 * @author wuyong
 *
 */
class Father
{
	void show()
	{
		System.out.println("father");
	}
}
/**
 * 子類Sun,繼承父類Father
 * @author wuyong
 *
 */
class Sun extends Father
{
	void show()
	{
		System.out.println("sun");
	}
	void print(){
		System.out.println("print");
	}
}
/**
 * java不支持多繼承,所以以下是錯誤的。
 * @author wuyong
 *
 */
//class C extends A,B{}


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

類中成員:

1,子父類中的變量

如果子類中出現非私有(private)的同名成員變量時,子類要訪問本類中的變量,用this;
子類要訪問父類中的同名變量,用super。


super的使用和this的使用幾乎一致。

this代表的是本類對象的引用。

super代表的是父類對象的引用。

示例代碼:

package com.itheima.base;

/**
 * 繼承
 * @author wuyong
 *
 */
public class FieldDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Father father1 = new Father();
		Sun sun = new Sun();
		sun.show();
		sun.showName();
	}

}
/**
 * 父類Father
 * @author wuyong
 *
 */
class Father
{
	public String name = "Father";
	private int num = 4;
	public void setNum(int num)
	{
		this.num =num;
	}
	public int getNum()
	{
		return this.num;
	}
}
/**
 * 子類Sun,繼承父類Father
 * @author wuyong
 *
 */
class Sun extends Father
{
	int num = 15;
	String name = "Sun";
	void show()
	{
		System.out.println(num);
	}
	void showName(){
		System.out.println("Father's name is " + super.name);
		System.out.println("Sun's name is " + this.name);
	}
}


2、子父類中的函數:

當子類出現和父類一模一樣的函數時,

當子類對象調用該函數,會運行子類函數的內容。

如同父類的函數被覆蓋一樣。

這種情況是函數的另一個特性:重寫(覆蓋)



當子類繼承父類,沿襲了父類的功能,到子類中,

但是子類雖具備該功能,但是功能的內容卻和父類不一致,

這時,沒有必要定義新功能,而是使用覆蓋特殊,保留父類的功能定義,並重寫功能內容。

覆蓋:

      1,子類覆蓋父類,必須保證子類權限大於等於父類權限,纔可以覆蓋,否則編譯失敗。

      2,靜態只能覆蓋靜態。



重載與重寫的區別:

重載:只看同名函數的參數列表。

重寫:子父類方法要一模一樣。

示例代碼:

package com.itheima.base;

/**
 * 繼承
 * @author wuyong
 *
 */
public class MethodDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Father father1 = new Father();
		father1.speak();
		Father father2 = new Sun();
//		father2.show();//無法調用子類的show方法,所有子類沒有重寫父類的show方法。
		Sun sun = new Sun();
		sun.show();
		sun.speak();
	}

}
/**
 * 父類Father
 * @author wuyong
 *
 */
class Father
{
	/**
	 * 父類show方法
	 * 私有的方法無法被子類繼承
	 */
	private int show()
	{
		System.out.println("Father's show");
	    return 1;
	}
	void speak()
	{	show();
		System.out.println("Father's speak");
	}
}
/**
 * 子類Sun,繼承父類Father
 * @author wuyong
 *
 */
class Sun extends Father
{
	/**
	 * 重寫了父類的方法
	 * /
	void speak()
	{
		 //調用父類的speak方法
	     super.speak();
	     System.out.println("Sun's speak");
	}
	/**
	 * 此方法並不是重寫父類的方法,而是新的方法
	 */
	int show() //Zi中的show()無法覆蓋Fu中的show()
	{
		System.out.println("Sun's show");
		return 0;
	}
}


3、子父類中的構造函數:

在對子類對象進行初始化時,父類的構造函數也會運行,

那是因爲子類的構造函數默認第一行有一條隱式的語句 super();

super():會訪問父類中空參數的構造函數。而且子類中所有的構造函數默認第一行都是super();


爲什麼子類一定要訪問父類中的構造函數?

因爲父類中的數據子類可以直接獲取。所以子類對象在建立時,需要先查看父類是如何對這些數據進行初始化的。

所以子類在對象初始化時,要先訪問一下父類中的構造函數。

如果要訪問父類中指定的構造函數,可以通過手動定義super語句的方式來指定。

注意:super語句一定定義在子類構造函數的第一行。


子類的實例化過程:

1.初始化父類的static成員。

2.初始化子類的static成員。

3.在棧和堆中定義子類變量並默認初始值,定義方法。

4.調用子類的構造方法運行了super();

5.調用父類的構造方法並立即執行父類的構造代碼塊。

6.給父類的變量默認初始化,然後顯示賦值。

7.父類構造方法繼續運行,定義父類的屬性和方法。
9.執行父類構造方法中其他語句(比如調用方法)。

10.執行子類的構造代碼塊

11.給子類變量賦值。

12.子類構造方法繼續執行,定義子類的屬性和方法。

13.再次給子類變量賦值。

14.執行子類構造方法中其他語句。


結論:

子類的所有的構造函數,默認都會訪問父類中空參數的構造函數。

因爲子類每一個構造函數內的第一行都有一句隱式super();

當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來指定要訪問父類中的構造函數。

當然:子類的構造函數第一行也可以手動指定this語句來訪問本類中的構造函數。

子類中至少會有一個構造函數會訪問父類中的構造函數。


示例代碼:

package com.itheima.base;

/**
 * 繼承
 * @author wuyong
 *
 */
public class InstanceDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Father father1 = new Sun();
		father1 = new Sun(10);
	}

}
/**
 * 父類Father
 * @author wuyong
 *
 */
class Father
{
	 static String name = "Father";
	 static{
		 System.out.println("staticBlock == " + name);
	 }
	 int num = 5;
	 Father()
     {
         //super();
         num= 60;
         System.out.println("Father run");
     }
	 Father(int num)
     {
         System.out.println("Father ...." + this.num);
     }
}
/**
 * 子類Sun,繼承父類Father
 * @author wuyong
 *
 */
class Sun extends Father
{
	 static String name = "Sun";
	 static{
		 System.out.println("staticBlock == " + name);
	 }
	 Sun()
     {
         super();  
         //super(4);
         System.out.println("Sun run");
     }
	 Sun(int num)
     {
		 //有了this()後,就沒有super()了,因爲this和super都必須是第一行數據,對對象進行初始化。
//         this();  
         //super();
         super(3);
         System.out.println("Sun..." + num);
     }
}


---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity開發</a>、<a href="http://www.itheima.com"target="blank">.Net培訓</a>、期待與您交流! ----------------------

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