super關(guān)鍵字
既然子類可以重寫父類的方法藤韵,那么如何區(qū)分調(diào)用的是繼承父類的方法還是子類自己重寫的方法鸟款?
看個(gè)例子
在之前的dog類中我們重寫了父類的eat方法磁椒,那么此時(shí)在sleep中調(diào)用的eat方法就應(yīng)該是重寫后的方法,如果需要調(diào)用父類的eat方法根蟹,就需要使用super關(guān)鍵字蕾域,將鼠標(biāo)懸停在方法上也可以查看此時(shí)方法所屬的類拷肌。
super使用
訪問父類成員方法,如super.eat();
訪問父類屬性旨巷,如super.name
實(shí)例化順序
父類構(gòu)造方法不允許被繼承巨缘,不允許被重寫,那么其存在的意義是什么?
添加相關(guān)測(cè)試代碼
public class Animal {
//(初始化順序7)
private String name = "小小"; //昵稱
protected int month = 2; //月份
private String species = "動(dòng)物"; //品種
//靜態(tài)屬性(初始化順序1)
private static int st1 = 22;
private static int st2 = 23;
static{
//(初始化順序2)
System.out.println("我是父類的靜態(tài)代碼塊");
}
{
//(初始化順序8)
System.out.println("我是父類的構(gòu)造代碼塊");
}
public Animal() { //(初始化順序6)
//(初始化順序9)
System.out.println("我是父類的無參構(gòu)造方法");
}
}
/**
* 貓
*/
public class Cat extends Animal{
private double weight; //體重
//靜態(tài)屬性(初始化順序3)
private static int st4 = 44;
static{
//(初始化順序4)
System.out.println("我是子類的靜態(tài)代碼塊");
}
{
//(初始化順序10)
System.out.println("我是子類的構(gòu)造代碼塊");
}
public Cat() { //(初始化順序5)
//(初始化順序11)
System.out.println("我是子類的無參構(gòu)造方法");
}
}
//測(cè)試
public class Test {
public static void main(String[] args) {
Cat one = new Cat(); //斷點(diǎn)位置
System.out.println(one.getWeight()); //0.0
//我是父類的靜態(tài)代碼塊
//我是子類的靜態(tài)代碼塊
//我是父類的構(gòu)造代碼塊
//我是父類的無參構(gòu)造方法
//我是子類的構(gòu)造代碼塊
//我是子類的無參構(gòu)造方法
}
}
分析程序執(zhí)行流程
- 調(diào)試運(yùn)行測(cè)試類,F(xiàn)5首先會(huì)進(jìn)入ClassLoader類赏胚,用于將需要的類加載到虛擬機(jī)中
- F6繼續(xù)會(huì)來到Animal類的靜態(tài)成員中,對(duì) st1 和 st2 進(jìn)行初始化又固,然后執(zhí)行父類的靜態(tài)代碼塊
- 繼續(xù)F6來到Cat類的靜態(tài)屬性中,對(duì) st4 進(jìn)行初始化煤率,然后執(zhí)行子類的靜態(tài)代碼塊
- 繼續(xù)F6回到
Cat one = new Cat();
中仰冠,F(xiàn)5進(jìn)入到Cat的無參構(gòu)造方法中,在按F5會(huì)來到父類的構(gòu)造方法蝶糯,(如果在按F5會(huì)來到Object類中) - 按F6洋只,會(huì)來到Animal的成員變量name上,依次對(duì)成員屬性進(jìn)行初始化,然后執(zhí)行構(gòu)造代碼塊识虚,然后回到父類的構(gòu)造方法
- 執(zhí)行完成后回到子類肢扯,因?yàn)樽宇惖某蓡T屬性 weight 沒有賦值操作,所以直接執(zhí)行子類的構(gòu)造代碼塊担锤,然后執(zhí)行子類的構(gòu)造方法蔚晨。最終回到main方法。
繼承后子類的初始化順序
首先完成類的加載肛循,加載過程中優(yōu)先加載父類的靜態(tài)成員铭腕,然后加載子類的靜態(tài)成員,在進(jìn)行子類的實(shí)例化過程中育拨,會(huì)逐層先去完成父類對(duì)象的構(gòu)造(成員屬性賦值谨履、構(gòu)造代碼塊欢摄、構(gòu)造方法)熬丧,然后再去完成子類對(duì)象的構(gòu)造(成員屬性賦值、構(gòu)造代碼塊怀挠、構(gòu)造方法)析蝴。
super()的使用
在子類中可以通過super關(guān)鍵字調(diào)用父類的成員屬性和方法。
上面已經(jīng)講解了子類對(duì)象在實(shí)例化時(shí)會(huì)去調(diào)用父類的無參構(gòu)造方法绿淋,那么子類是否有權(quán)利選擇調(diào)用什么形式的父類構(gòu)造呢闷畸?
在java中是使用 super()
方法對(duì)父類構(gòu)造方法進(jìn)行調(diào)用。
使用說明
- 子類的構(gòu)造的過程中必須調(diào)用其父類的構(gòu)造方法
- 如果子類的構(gòu)造方法中沒有顯示調(diào)用父類的構(gòu)造方法吞滞,則系統(tǒng)系默認(rèn)調(diào)用父類無參的構(gòu)造方法佑菩,也就是會(huì)默認(rèn)先執(zhí)行
super();
如果父類未提供默認(rèn)無參構(gòu)造則編譯出錯(cuò) - 可以通過
super()
調(diào)用父類允許被訪問的其他構(gòu)造方法,包括帶參和不帶參的 - 使用
super()
調(diào)用父類指定構(gòu)造方法裁赠,必須在子類的構(gòu)造方法有效代碼的第一行
總結(jié)super作用
- 訪問父類成員方法
- 訪問父類屬性
- 訪問父類構(gòu)造方法
super vs this
this:
當(dāng)前類對(duì)象的引用殿漠,用于訪問當(dāng)前類的成員以及構(gòu)造方法
super:
父類對(duì)象的引用,用于訪問父類的成員以及構(gòu)造方法
- this和super都不能在靜態(tài)方法中使用
- 構(gòu)造方法調(diào)用時(shí)佩捞,super和this不能同時(shí)出現(xiàn)
這其實(shí)不違背子類的構(gòu)造的過程中必須調(diào)用其父類的構(gòu)造方法绞幌,因?yàn)椴还墚?dāng)前子類構(gòu)造如何互相調(diào)用,最后那個(gè)被調(diào)用的子類構(gòu)造方法(如果沒有顯示調(diào)用父類構(gòu)造方法)一定會(huì)調(diào)用父類無參構(gòu)造方法