-
覆蓋方法
超類中有些方法對于子類并不適用,為此子類需要覆蓋超類的方法。
子類和超類方法簽名(方法名+參數列表)相同,則為覆蓋方法。
覆蓋方法的返回類型(可協(xié)變返回類型)
返回類型不是方法簽名的一部分,覆蓋方法時要保證返回類型的兼容性,允許子類覆蓋方法返回類型是超類返回類型的子類型。
內聯(lián)
一個方法沒有被覆蓋并且很短,編譯器會對其進行優(yōu)化,避免動態(tài)綁定帶來的系統(tǒng)開銷。
-
重載方法
方法名稱相同,參數列表不相同的方法為重載方法,一個類中就可以存在這樣的關系,而覆蓋是子類方法和超類方法之間的關系。
-
私有域的訪問問題
盡管每個子類對象都擁有超類的私有域,但是在子類的方法中不能直接訪問這個私有域,必須通過訪問器訪問。
例如:
Employee.java
public class Employee{
private double salary;
...
public LocalDate getHireDay(){
return hireDay;
}
}
Manager.java
public class Manager extends Employee{
public double getSalary(){
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
/* error:子類方法不能訪問超類的私有域
public double getSalary(){
double baseSalary = salary;
return baseSalary + bonus;
}
*/
}
-
super與this
this:返回對象的引用;
super:返回的不是對象引用,不能將super賦值給一個對象變量,只是一個指示編譯器調用超類方法的特殊關鍵字。
-
方法調用
假設存在x.f(param),x為C類的一個對象。則會先篩選C類中所有名為f的方法和C類的超類的public的f方法(C不能直接訪問超類的私有域和私有方法);
編譯器查看參數類型,若找到匹配的,找不到可以使用類型轉換,則直接選擇這個方法(重載過程);
若出現(xiàn)private、static、final方法,則直接是靜態(tài)綁定,因為這些都是本類才能調用的方法,不依賴于對象。而調用方法依賴于隱式參數的實際類型,則是動態(tài)綁定;
運用了動態(tài)綁定時,首先在實際類型的類里找方法,若找不到再去實際類型的超類里面找。
方法表
為了減小查找方法的開銷,虛擬機使用了方法表;
假設D是C的子類,則調用d.f(param)方法時,首先去D的方法表中找;
若查找不到,則到C的隱式參數方法表中查找(依賴于隱式參數的方法,即非private、sstatic、final)。
-
超類與子類方法可見性
子類覆蓋超類方法時,子類方法可見性不能低于超類方法可見性,如超類使用了public,則子類也要使用public。因為如果不這么做,c引用了子類D的一個對象d,調用c.fun(param)(可見性為public),而D類對fun的可見性為private,則必然會出錯。
-
阻止繼承——使用final
希望阻止人們利用某個類定義子類,不允許被拓展的類被稱為final類。
final類中所有的方法也默認被聲明為final(即使沒有顯式寫出來),但域并沒有被默認聲明為final。
子類不能覆蓋final方法,因此final方法也是靜態(tài)綁定的。
將類或方法聲明為final的主要目的
防止子類覆寫方法,確保他們在子類中語義不變。
-
強制類型轉換
將一個子類引用賦給超類變量不需要強制轉換;
將一個超類引用賦給子類變量需要類型轉換。
例如如下超類賦給子類(Manager extends Empolyee):
Employee[] employees = new Employee[3];
Manager managerOld = new Manager();
//子類引用賦值給超類變量不需要強制類型轉換
employees[0] = managerOld;
employees[1] = new Employee();
/**
*盡管employee[0]引用的實際類型是Manager
*但編譯器并不知道
*表面還是超類引用
*賦值給子類變量需要強制類型轉換
*/
Manager managerNew = (Manager)employees[0];
/**
*養(yǎng)成良好習慣,提前判斷引用的實際類型,防止向下類型轉換的“謊報”錯誤
*/
if(employee[1].instanceof Manager){
//由于employees[1]實際類型是Employee,因此不會執(zhí)行
Manager boss = employees[1];
}
- 特點
向下類型轉換時需要使用強制類型轉換;
只能在繼承層次內進行強制類型轉換;
將超類轉換為子類前,需要使用instanceof檢查實際類型;
如果只是需要子類的覆蓋方法,可以不轉換,因為動態(tài)綁定可以準確調用到子類的覆蓋方法;
只有需要使用子類特定方法或域時才需要強制類型轉換;
-
受保護訪問
任何被聲明為private的域和方法都不能被其他類訪問,包括子類;
使用受訪問保護的protected讓子類可以訪問超類某個域,但是例如Manager可以訪問Manager對象某個protected域,但是不能訪問Employee對象的protected域。