繼承
在現實世界中,狗和貓都是動物,這是因為他們都有動物的一些共有的特征。
在Java中,可以通過繼承的方式來讓對象擁有相同的屬性,并且可以簡化很多代碼
例如:動物都有的特征,有名字,有年齡,那么讓貓和狗都繼承于動物,這樣貓和狗就也有了名字和年齡。
需要使用的關鍵字:extends
class Animals{int age;String name;
}class Dogs extends Animals{String height;
}class Cats extends Animals{String weight;
}
通過繼承的方式就能讓dog和cat繼承animals的age和name屬性。并且不止屬性,父類中的方法也是可以繼承的。
但是要是父類和子類中的屬性名或者方法名因為某些原因重名了呢?
父類成員變量、成員方法訪問
如果屬性名相同,那么則會優先訪問自己的,而不是父類的:
public class Base {int a;int b;int c;}public class Derived extends Base{int a; char b; public void method(){a = 100; b = 101; c = 102; }}
成員變量訪問遵循就近原則,自己有優先自己的,如果沒有則向父類中找。
例如上面的會優先訪問class Derived中有的,如果沒有再訪問到Base中的。
方法同理,也是優先訪問子類的再訪問父類的;但是方法有個特殊的點:
如果子類父類方法是重名的但是形成重載了,也就是參數列表不同,那么會優先匹配重載的那個方法。
super關鍵字
如果父類和子類是重名的,但是想要訪問父類的方法,這個時候就可以使用super關鍵字,使得拿到的對象/方法直接就是父類的。
class Animal {void eat() {System.out.println("這里是父類");}
}class dog extends Animal {void eat() {super.eat();System.out.println("這里是子類");}
}
這樣就會先拿到父類中的eat方法,然后再打印子類中的相關語句。
super同樣可以適用成員變量:
class Animal {String name = "Animal";
}class Dog extends Animal {String name = "Dog";void printName() {System.out.println(super.name);System.out.println(this.name);}
}
super和this的區別
相同點:
- 都是Java中的關鍵字
- 只能在類的非靜態方法中使用,用來訪問非靜態成員方法和字段
- 在構造方法中調用時,必須是構造方法中的第一條語句,并且不能同時存在
不同點:
- this是當前對象的引用,而super相當于是子類對象中從父類繼承下來部分成員的引用
- 在非靜態成員方法中,this用來訪問本類的方法和屬性,super用來訪問父類繼承下來的方法和屬性
- 在構造方法中:this(...)用于調用本類構造方法,super(...)用于調用父類構造方法,兩種調用不能同時在構造方法中出現
- 構造方法中一定會存在super(...)的調用,用戶沒有寫編譯器也會增加,但是this(...)用戶不寫則沒有
初始化順序
class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;System.out.println("構造方法執行");}{System.out.println("實例代碼塊執行");}static {System.out.println("靜態代碼塊執行");}}
在上面這個代碼中,執行的順序是先執行靜態的,再執行實例的,再執行構造方法;那在有繼承關系的代碼塊中是什么樣子呢?
class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;System.out.println("Person:構造方法執行");}{System.out.println("Person:實例代碼塊執行");}static {System.out.println("Person:靜態代碼塊執行");}}class Student extends Person{public Student(String name,int age) {super(name,age);System.out.println("Student:構造方法執行");}{}System.out.println("Student:實例代碼塊執行");static {System.out.println("Student:靜態代碼塊執行");}}
上面的代碼執行結果如下:
- Person: 靜態代碼塊執行
- Student:靜態代碼塊執行
- Person: 實例代碼塊執行
- Person: 構造方法執行
- Student:實例代碼塊執行
- Student:構造方法執行
先是父類和子類靜態方法執行,然后再是父類的實例和構造方法,再試子類的示例和構造方法。
final關鍵字
final關鍵可以用來修飾變量、成員方法以及類。
修飾變量
修飾變量或字段,表示常量(即不能修改)。
inal int a = 10;a = 20; // 編譯出錯
修飾類
表示此類不能被繼承。
inal public class Animal {...}public class Bird extends Animal {...}
編譯出錯。
修飾方法
表示該方法不能被重寫
多態
簡單地說,就是使用不同的對象去完成時會產生出不同的狀態,所以叫做多態。
在java中要實現多態,必須要滿足如下幾個條件,缺一不可:
- 必須在繼承體系下
- 子類必須要對父類中方法進行重寫
- 通過父類的引用調用重寫的方法
多態體現:在代碼運行時,當傳遞不同類對象時,會調用對應類中的方法。
class People{public void eat(){System.out.println("吃飯");}
}class Boy extends People{@Overridepublic void eat(){System.out.println("男孩子吃飯");}
}class Girl extends People{@Overridepublic void eat(){System.out.println("女孩子吃飯");}
}
public class demo12_Polymorphism2 {public static void main(String[] args) {People people = new People();Boy boy = new Boy();Girl girl = new Girl();people.eat();boy.eat();girl.eat();}
}
people.eat();
?將調用?People
?類的?eat
?方法,并打印 "吃飯"。boy.eat();
?將調用?Boy
?類重寫的?eat
?方法,并打印 "男孩子吃飯"。girl.eat();
?將調用?Girl
?類重寫的?eat
?方法,并打印 "女孩子吃飯"。
重寫和重載
重寫:
class dog {public void bark(){System.out.println("wangwangwang");}
}class pipi extends dog {@Overridepublic void bark(){System.out.println("houhouhou");}
}
訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類方法被public修飾,則子類中重寫該方法就不能聲明為 protected
父類被static、private修飾的方法、構造方法都不能被重寫。
重載:
class dog {public void bark(){System.out.println("wangwangwang");}public void bark(int num){System.out.println("houhouhou");}
}
向上轉型和向下轉型
向上轉型
Animal animal = new Cat("狗狗");
通過父類,新建一個子類的成員,這就是向上轉型。
向上轉型的優點:讓代碼實現更簡單靈活。
向上轉型的缺陷:不能調用到子類特有的方法。
向下轉型
將一個子類對象經過向上轉型之后當成父類方法使用,再無法調用子類的方法,但有時候可能需要調用子類特有的方法,此時將父類引用再還原為子類對象即可,即向下轉換。
向下轉型用的比較少,而且不安全,萬一轉換失敗,運行時就會拋異常。
Java中為了提高向下轉型的安全性,引入 了instanceof,如果該表達式為true,則可以安全轉換。
public class DowncastingExample {public static void main(String[] args) {// 向上轉型:創建 Cat 類型的實例并賦值給 Animal 類型的引用Animal animal = new Cat("狗狗");// 下面進行向下轉型,嘗試將 Animal 類型的引用轉換為 Cat 類型// 在轉型之前,我們首先檢查 animal 是否確實引用了 Cat 類的實例if (animal instanceof Cat) {// 安全進行向下轉型Cat myCat = (Cat) animal;System.out.println("向下轉型成功,貓的名字是:" + myCat.name);} else {System.out.println("引用的不是 Cat 類型的實例,轉型失敗。");}}
}
使用多態的好處
1. 能夠降低代碼的 "圈復雜度", 避免使用大量的 if - else
2. 可擴展能力更強
多態缺陷:代碼的運行效率降低。