java-day20
子類構造器中爲什麼要調用父類的構造器?
- 子類繼承了父類,那麼就把父類中的屬性和方法都繼承了過來,但是我們希望子類中繼承過來的屬性都是已經在父類中完成了初始化工作之後的,因爲這樣我們就可以拿着這些屬性直接使用了,父類中對這些屬性完成初始化工作的代碼默認就在構造器中,所以我們子類構造器裏面首先會調用父類中的構造器,先完成對父類中屬性的初始化工作,然後再執行子類自己的構造器中的代碼,如果我們對父類構造器中初始化的工作不滿意,那麼我們還可以在子類構造器的代碼中對繼承過來的屬性進行修改,以便覆蓋掉父類初始化的值。
super關鍵字
-
子類繼承父類之後,在子類可以使用關鍵字訪問子類中的屬性、方法、構造器,也可以在子類中使用super關鍵字表示訪問父類中的屬性、方法、構造器。
-
1、訪問父類中的屬性
-
如果父類中的屬性name被繼承了,子類中有寫了一個自己的屬性那麼,那麼這時候this和super就可以區分我們訪問的name到底是哪一個name屬性。
-
public class Person{ protected String name = "張三"; } public class Student extends Person{ private String name = "李四"; public void test(){ System.out.println(name); //this和super可以區分是哪個name System.out.println(this.name); System.out.println(super.name); } }
-
如果父類中的屬性,是private修飾的,那麼使用super也是不能訪問的。
-
public class Person{ private String name = "張三"; } public class Student extends Person{ private String name = "李四"; public void test(){ //編譯報錯,無法訪問父類的private System.out.println(super.name); } }
如果父類中的屬性name被繼承了,子類中也沒自己定義新的name屬性,那麼這時候,直接使用name和this . name和super.name這三種方式訪問都是同一個name屬性
public class Person{ protected String name = "張三"; } public class Student extends Person{ public void test(){ System.out.println(name); System.out.println(this.name); System.out.println(super.name); } }
-
-
-
2、調用父類中的方法
-
//例如: public class Person{ public void run(){ System.out.println("person run.."); } } public class Student extends Person{ public void run(){ System.out.println("student run.."); } //在這裏可以訪問到自己類中的run方法 //也可以訪問到父類中的run方法 //爲了區分調用的是哪一個run方法 //可以使用this和super public void test(){ run(); this.run(); super.run(); } }
-
如果調用或訪問的時候,沒有因爲同名而帶來的歧義的話,可以不使用this或者super,直接通過方法名或者屬性名進行調用就可以了。
-
-
3、調用父類中的構造器
-
public class Person{ } public class Student extends Person{ //默認使用super()調用父類無參構造器 public Student(){ } }
public class Person{ protected String name; public Person(String name){ this.name = name; } } public class Student extends Person{ //編譯報錯 //默認執行super() //父類沒有無參構造器 public Student(){ } }
public class Person{ protected String name; public Person(String name){ this.name = name; } } public class Student extends Person{ //編譯通過 //手動使用super調用父類無參構造器 //顯示調用 public Student(){ super("Tom"); } }
注意:無論是隱式調用還是顯示調用super語句一定要在子類構造器中的第一行
public class Person{ protected String name; public Person(String name){ this.name = name; } } public class Student extends Person{ //編譯報錯 public Student(){ System.out.println("...."); super("Tom"); } }
注意:在子類的構造器中可以使用this()來調用子類的構造器,可以使用super()來調用父類的構造器,但是他們不能同時出現(因爲都要放在第一行)
總結:在創建一個子類對象的時候,肯定要調用到子類中的一個構造器,並且在子類構造器執行之前,一定是會先調用到父類中的構造器的。這樣做的目的就是在子類的構造器執行之前,先執行父類的構造器完成對父類中屬性的初始化,保證子類繼承的父類中的屬性是已經初始化好可以直接使用的。
-
-
方法的重寫(覆蓋)
-
方法的重寫,存在於子類和父類之間(包括直接父類可以是間接父類),之前學習過的方法的重載是存在於同一個類中。
- 方法的重載:同一個類中
- 方法的重寫:子類和父類之間
-
父類中的靜態方法,在子類中是不能重寫的
-
父類中的靜態方法,不能被子類中重寫爲非靜態方法
-
Person: public static void showInfo(){ } Student: public void showInfo(){ }
-
Person: public void showInfo(){ } Student: public static void showInfo(){ }
-
Person: public static void showInfo(){ } Student: public static void showInfo(){ }
編譯通過,但是不是重寫,重寫只能發生在子父類之間的非靜態方法上。重寫只能發生在子父之間非靜態方法上。因爲靜態方法是屬於類的,可以類名直接調用,它和對象沒有關係的。 -
父類中的非靜態方法,可以被子類中繼承並且重寫,但是重寫的時候也必須是非靜態方法。這個就是正常的方法重寫現象。
-
-
-
父類中的私有方法不能被子類重寫
-
子類繼承父類後,同時也繼承到父類中的方法,如果需要對某個方法進行重寫,那麼這個被繼承的方法需要滿足以下條件:
-
必須是非靜態的方法
-
該方法在子類中必須可以直接訪問的
-
public class Person{ private void test(){} } //編譯通過但不是重寫,就是兩個類中有相同名字的兩個私有方法而已 public class Student extends Person{ private void test(){} }
-
-
-
方法重寫的語法要求
-
方法名必須相同
-
參數列表必須相同
-
訪問控制修飾符可以相同也可以不同,可以擴大但是不能縮小
- public > protected > default > private
-
方法拋出的異常類型可以相同也可以不同,可以縮小但是不能擴大
- 異常類型的範圍大小根據類型中的子父類關係來確定的
- Exception異常類型是ArraysIndexOutOfBoundException的父類型
- 範圍:Exception > ArraysIndexOutOfBoundException
-
方法的返回類型可以相同,也可以不同,如果不同的話,重寫之後方法的返回類型必須是原方法的返回類型的子類型(兼容)
-
例子1:
-
Person.java
-
protected Object showInfo() throws Exception{ return null; }
-
Student.java
-
protected Object showInfo() throws Exception{ return null; }
-
-
例子2:
-
Person.java
-
protected Object showInfo() throws Exception{ return null; }
-
Student.java
-
//沒有異常也是縮小 public Object showInfo(){ return null; }
-
-
-
如果各個部分都和父類中方法保持一致,那麼這個方法的重寫我們重寫的是什麼?
- 我們主要重寫的是方法中的代碼,所以大多數情況方法聲明部分和父類中的方法保持一致。
-
爲什麼要對從父類中繼承過來的方法進行重寫?
- 子類中繼承過來的方法,原來是定義在父類中的,現在被子類繼承了,而子類本身又是對父類型的擴展,所以這個時候,從父類中繼承過來的方法,可能在子類中已經不是很適用了,所以我們需要重寫對這個方法進行重寫。