java基礎--多態_抽象類

概念

多態性是面向對象編程的又一個重要特徵,它是指在父類中定義的屬性和方法被子類繼承之後,可以具有不同的數據類型或表現出不同的行爲,

對面向對象來說,多態分爲編譯時多態和運行時多態。

編譯時多態是靜態的,主要是指方法的重載,它是根據參數列表的不同來區分不同的方法。通過編譯之後會變成兩個不同的方法,在運行時談不上多態。
運行時多態是動態的,它是通過動態綁定來實現的,也就是大家通常所說的多態性。

Java 實現多態有 3 個必要條件

繼承、重寫和向上轉型。
繼承:在多態中必須存在有繼承關係的子類和父類。
重寫:子類對父類中某些方法進行重新定義,在調用這些方法時就會調用子類的方法。
向上轉型:在多態中需要將子類的引用賦給父類對象,只有這樣該引用才既能可以調用父類的方法,又能調用子類的方法。


這裏提一下向上轉型和向下轉型

向上轉型

  1. 向上轉型概念

隱式轉型、自動轉型,父類引用指向子類實例,小類轉型爲大類。
如 Animal two=new Dog();//Dog類是Animal類的子類
向上轉型是安全的,任何子列都繼承並接受了父類的方法,狗屬於動物。但是向下轉型不可以,不能說動物就是狗這是不成立的,(向下轉型要通過強制類型轉換)

  1. 應用:

    1)、當一個子列對象向上轉型父類類型之後,就被當成了父類對象,能調用的方法會減少 可以調用子類重寫父類的方法(此處調的是子類的方法)以及父類派生的方法,無法調用子類獨有方法

    2)、父類中的靜態方法無法被子類重寫,
    例如父類的靜態方法

		public static void say(){
	System.out.println("動物叫...");
}

子類中也有一個同名的靜態方法,此時say()屬於子類自己獨有的方法,不構成重寫(可以用@Override註解判斷是否是重寫)

public static void say(){
	System.out.println("小狗汪汪叫...");
}
 Animal two=new Dog();
 two.say();//此時調用的是父類靜態方法say(),打印:動物叫...

所以向上轉型之後,只能調用到父類原有的靜態方法

多態的實現可以通過向上轉型和動態綁定機制來完成,向上轉型實現了將子類對象向上轉型爲父類對象類型,二動態綁定機制能識別對象轉型前的類型,從而自動調用該類的方法,

動態綁定:
綁定就是將一個方法調用同一個方法所在的類連接到一起,綁定分爲靜態綁定和動態綁定兩種。
靜態綁定:在程序運行之前進行綁定(由編譯器和鏈接程序完成)
例如:
Dog dog = new Dog();
dog.say();
這種調用在代碼裏指定,編譯時編譯器就知道調用dog類中的say()方法

動態綁定:在程序運行期間由JVM根據對象的類型自動的判斷應該調用哪個方法,

Animal [] animals = new Animal[5];
for(int i = 0; i < animals.length; i++){
	int n = (int)(Math.random() *2);//隨機產生0到1中的一個數
	switch (n){
		case 0:
			animals[i] = new Cat();
			break;
		case 1:
			animals[i] = new Dog();
			break;
	}
}

for (int i = 0; i < animals.length; i++){
	animals[i].eat();
}

在編譯過程中不知道調用哪個類的eat()方法,直到運行時才能到底調用哪個類的eat方法,這種就是動態綁定
--------------------------------------------------

向下轉型

子類引用指向父類對象,需要強制類型轉換
如:

Animal two=new Dog();
Dog dog = (Dog)two;//此處必須進行強制類型轉換

向下轉型後,可以調用子類特有的方法

但是必須滿足轉型條件才能進行強轉

Animal animal = new Dog();
Dog dog = (Dog) animal;  //正確寫法
Cat cat = (Cat) animal;  //這種寫法不正確,編譯報錯Exception in thread "main" java.lang.ClassCastException: com.imooc.animal.Dog cannot be cast to com.imooc.animal.Cat

這個時候可以用instanceof運算符進行判斷:返回true/false

Animal animal = new Dog();
if (animal instanceof Dog) {
	Dog dog = (Dog) animal;
	System.out.println("dog...");
}else if (animal instanceof  Cat){
	Cat cat = (Cat) animal;
	System.out.println("cat...");
}

抽象類和抽象方法

1. 概念

在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象方法也是同一個道理。
使用abstract class來定義抽象類
例如:

//抽象類:不允許實例化,可以通過向上轉型,指向子類實例
public abstract class Animal {
	
	public Animal(){	
	}
	//抽象方法:不允許包含方法體;子類中需要重寫父類的抽象方法,否則,子類也是抽象類
	//static final private不能與abstract並存
	public abstract void eat();
	}

2. 特點:

1.抽象方法不能被直接實例化
它只能作爲其他類的父類,但可以向上轉型,指向實例化

//Animal是抽象類的錯誤示範:
Animal Animal  = new Animal();//直接new是錯誤的

2.抽象方法只有聲明,不能有實現。
例如:

public abstract void eat();

3. 意義:

爲其子類提供一個公共的類型。
封裝子類中的重複內容(成員變量和方法)
將父類設計成抽象咧後,即可藉由父子繼承關係限制子類設計隨意性,在一定程度上避免了無父類的實例化

4. 重點:

1.含有抽象方法的類,只能被定義成抽象類
在這裏插入圖片描述
正確的寫法
在這裏插入圖片描述
2.抽象類不一定包含抽象方法
3.在抽象類中的成員方法可以包括一般方法和抽象方法
4.抽象類不能被實例化,即使抽象類中不包含抽象方法,這個抽象咧也不能創建實例。抽象類的構造方法主要是用於被其子類調用
5.一個類繼承抽象類後,必須實現其所有抽象方法,否則也是抽象類,不同子類對父類的抽象方法可以有不同的實現。
6.即使父類是具體的,但其子類也可以是抽象的,如object類是具體的類,但是可以創建抽象子列
7.abstract方法不能用static和private修飾,
對於類,不能同時用final和abstract修飾,因爲final關鍵字使得類不可繼承,而abstract修飾的類如果不可以被繼承將沒有任何意義。

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