封裝繼承多型的複習
super關鍵字
定義:super代表父類引用,用於引用父類的屬性和方法。
note:
-
訪問時不能訪問private屬性和方法,super.屬性名;super.方法名(引數);
2. super用於子類構造器的注意點:必須在構造器第一行,不能與this()共存在同一構造器,如果子類構造器不寫super或this則預設存在一個super方法呼叫父類的無參構造器。
3. super();只能用於子類的構造器第一行。
對於子類中與父類同名的屬性或方法,使用this訪問子類,用super訪問父類。
若不使用關鍵字使用子類中某一方法或屬性,遵循jvm繼承的記憶體模型規則:即1.先查早本類,有則直接呼叫。2.沒有則查其父類,有則呼叫,若有但是私有方法,則報錯。3.父類沒有則繼續往上查詢,直到object以此類推。
this與super的區別
重寫/覆蓋(override)
定義: 子類有一個方法和其父類的某個方法,名稱,引數列表都相同,但是方法體不同,則稱該子類重寫了父類。
note:
-
子類方法的名稱和引數列表要完全相同。
-
子類與父類的返回值不需一致,子類的返回值可以是父類返回值的子類(但不能是父類返回值的父類或不相關類,否則編譯報錯),也將構成重寫。如:父類返回 Object類,子類返回String類
-
子類中不能縮小父類方法的訪問許可權。public > protected > default > private
練習
overload與override的區別
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String say() {
return " 我的名字是:" + this.name + " 我的年齡是:" + this.age;
}
}
public class Student extends Person{
private int id;
private int score;
public Student(String name, int age, int id, int score) {
super(name, age);
this.id = id;
this.score = score;
}
public String say(){
return super.say() +" 我的id是:" + this.id + " 我的分數是:" + this.score;
}
}
public class Test {
public static void main(String[] args) {
Student kuang = new Student("kuang", 18, 111333, 99);
Person lxly = new Person("lxly", 26);
System.out.println(lxly.say());
System.out.println(kuang.say());
}
}
多型(polymorphic)
簡單來說,多型就是指方法或物件有多種形態,多型是建立在封裝和繼承的基礎上的。
-
方法的多型,如過載和重寫。
-
物件的多型!(核心)
-
一個物件的編譯型別和執行型別可以不一致
-
編譯型別在定義物件時,就確定了不能改變
-
執行型別可以改變
-
編譯型別看定義是 = 左邊,執行型別看 = 右邊
-
例子:
public class Animal {
public void shout(){
System.out.println("Animal shout() wow!");
}
}
public class Dog extends Animal {
public void shout() {
System.out.println("Dog shout wow!");
}
}
public class Cat extends Animal {
public void shout() {
System.out.println("Cat shout wow!");
}
}
public class Application {
public static void main(String[] args) {
//animal編譯型別是Animal 執行型別是Cat
Animal animal = new Cat();
animal.shout();
System.out.println("=============");
//animal編譯型別是Animal 執行型別是Dog
animal = new Dog();
animal.shout();
}
}
還有一種用法:在方法的引數列表中寫父類,但傳入子類作為引數,達到多型目的。
向上轉型
定義:父類的引用指向了子類的物件。
多型的前提是繼承關係。
-
本質:父類的引用指向子類
-
語法:父類型別 引用名 = new 子類型別();
-
特點:編譯型別看左邊,執行型別看右邊。
可以呼叫父類中的成員方法(需遵守訪問許可權),不能呼叫子類的特有成員屬性/方法,最終執行效果看子類的具體實現。(動態繫結)
因為在編譯階段,能呼叫那些成員,是由編譯型別決定的,所以在父類引用指向子類的例子中,引用物件如果直接呼叫子類特有成員,將會報錯無法通過編譯。但是,一旦編譯通過以後,開始執行時,則會將引用物件當作子類,遵循子類繼承的記憶體模型原則。舉個例子,呼叫方法時,如果子類(執行型別)對父類的方法進行了重寫,那麼父類的引用會呼叫子類重寫的方法。
向下轉型
-
語法:子類型別 引用名 = (子類型別)父類引用
-
只能強轉父類的引用,不能強轉父類的物件
-
要求父類的引用必須指向的是當前目標型別的物件(原來A的引用指向B,A才可以向下轉型為B),
A a = new B();//A的引用指向B
B b = (B)a;//向下轉型
//((B)a).show(); show()是B的獨有方法。 -
向下轉型後,可以呼叫子類型別中所有的成員
細節
-
屬性與重寫無關,屬性值看編譯型別(等號左邊)
-
instanceof 比較操作符,用於判斷物件型別是否是xx型別或xx型別的子型別。(判斷的是執行型別)
練習
注意:b == s;//true,判斷的是實際指向的物件是否一致。
動態繫結
-
當呼叫物件方法時,方法會和該物件的執行型別繫結,先從執行物件的類裡找方法,沒有再去父類找,遵循繼承記憶體模型。
-
當某一方法呼叫屬性時,沒有動態繫結,即該方法在哪兒,呼叫的屬性就在哪兒。(哪裡宣告,哪裡使用)
應用
public class Test {
public static void main(String[] args) {
Person[] people = new Person[5];
people[0] = new Person(30, "jack1");
people[1] = new Student(15, "luna", 90);
people[2] = new Student(16, "Smith", 88);
people[3] = new Teacher(36, "james", 5000);
people[4] = new Teacher(39, "judy", 7000);
for (int i = 0; i < people.length; i++) {
System.out.println(people[i].say());
if (people[i] instanceof Student)
((Student) people[i]).study();
if (people[i] instanceof Teacher)
((Teacher) people[i]).teach();
}
}
}
public class Test {
public void showEmpAnnual(Employee e){
System.out.println(e.getAnnual());//動態繫結
}
public void testWork(Employee e){//向上轉型
if (e instanceof Manager)
((Manager) e).manage();//向下轉型
else if (e instanceof UsualEmp)
((UsualEmp) e).work();
}
public static void main(String[] args) {
Manager manager = new Manager("li",8955,5000);
UsualEmp usualEmp = new UsualEmp("jack",7000);
Test test = new Test();
test.testWork(manager);//向上轉型
test.testWork(usualEmp);
test.showEmpAnnual(manager);
test.showEmpAnnual(usualEmp);
}
}
Object類詳解
==和equals的對比
== 是一個比較運算子
-
既可以判斷基本型別,又可以判斷引用型別
-
如果判斷基本型別,則判斷的是值是否相等
-
如果判斷的是引用型別,則判斷的是地址是否相等,即是否指向同一物件
equals方法是Object的方法
-
只能判斷引用型別
-
預設的判斷是地址是否相同。
但JDK原始碼中有些類已經重寫了equals方法,如String Integer,它們的equals比較的是值是否相等。
hashCode()方法 初見
-
作用是提供具有雜湊結構容器的效率
-
兩個引用,如果指向的額是同一個物件,則雜湊值肯定是一樣的
-
兩個引用,如果指向的是不同的物件,則雜湊值不一樣。
-
雜湊值主要是根據地址號來的,但不能完全將雜湊值等同於地址。
toString
-
預設返回:全類名 + @ + 雜湊值的十六進位制 (即Object的toString方法)
-
重寫toString方法,列印物件或拼接物件時,都會自動呼叫該物件的toString
-
當直接輸出一個物件時,toString方法會被預設呼叫。
finalize (不常用)
-
當物件被回收時,系統自動呼叫該物件的finalize方法,子類也可以重寫該方法。
-
回收時機:當某個物件沒有任何引用時,系統會決定什麼時候(有一套自己的演算法)使用垃圾回收機制來銷燬物件,程式設計師也可以通過System.gc()主動呼叫
public class Finalize {
public static void main(String[] args) {
Car bmw = new Car("325li");
bmw = null;
//這時 car物件就是一個垃圾 垃圾回收器就會回收(銷燬)物件(不是立即回收)
//程式設計師就可以在finalize中,寫自己的業務邏輯(如釋放資源:資料庫連線,或開啟檔案
//如果程式設計師不重寫,那麼就會預設呼叫Object的finalize
System.gc();//主動呼叫垃圾回收器
System.out.println("程式退出");
}
}
class Car{
private String name;
public Car(String name) {
this.name = name;
}
斷點除錯
-
斷點除錯用於檢視原始碼執行過程,從而發現錯誤所在。
-
在斷點除錯中,是以物件的執行型別來執行的。
-
可以在除錯的過程中動態加入斷電,快捷鍵f9可以直接跳入下一個斷點。
-
進入方法可以進入jdk原始碼中的方法。
-