關于Java中重載和重寫的一些問題
重載:
概念:
指 在一個類中,多個方法(包括構造方法)的方法名相同,但是形參清單不同,即參數個數、類型、順序不同。調用時,Java虛拟機(JVM)會根據傳入的實參清單,去選擇合适的方法執行。
重載,是一個類中 多态的表現;
注意:
1.不能對 通路權限、傳回類型、抛出的異常 進行重載;
2.使用重載時隻能通過不同的形參清單,且必須具有不同的清單;
3.異常的類型和數目不會影響重載;
舉例:
1.傳回類型不同 或者 參數類型相同,順序不同,不能重載
public static int add(int a,int b){
return (a+b);
}
public static long add(int a,int b){
return (a+b);
}
2.參數類型,個數、順序 不同 可以 重載(可以有不同的 通路權限,傳回類型)
public static void main(String[] args) {
// 根據 傳入實參不同 調用相應的方法
add(,'s'); // 注意 此處 沒有比對到 方法,則會 隐式轉換,就近原則轉換。
add(,L);
add(L,);
}
// 測試 方法的重載
public static int add(int a,int b){
System.out.println("1.111");
return (a+b);
}
private static long add(int a,long b){
System.out.println("2.2222");
return (a+b);
}
protected static int add(long b,int a){
System.out.println("3.333");
return (int) (a+b);
}
重寫:
概念:
首先,重寫,是針對,繼承關系的父類和子類之間關系的。
子類繼承父類,繼承了父類中所有(非私有,不同包則 非預設)屬性和方法,
當子類可以根據需要修改父類的方法,擴充其功能,這樣的操作就稱為
重寫,也叫覆寫/覆寫.重寫:是指子類中的方法與父類中繼承的方法有完全相同的傳回值類型、方法名、參數個數以及參數類型。
重寫規則:
==”兩同兩小一大“規則==
”兩同“:方法名,形參清單 相同;
“兩小”:子類的 傳回值類型,抛出的異常,小于父類;
比如:父類抛出IOException 則子類隻能抛出 同類型以及 其子異常;
“一大”:子類的 通路權限,大于 父類的 通路權限;
比如:父類是 預設 權限,則子類隻能是同權限或者 protected或者
public(注意,預設權限,異包子類不能通路)。
調用規則:
對于 父類對象:
調用的是 自身的 方法;
對于子類對象:
F s = new S();// 父類變量 指向 子類 執行個體
s.add();
調用的是 重寫的 方法,當子類沒有重寫父類的 方法時 ,調用的是 父類的方法。
public static void main(String[] args) {
F f = new F();
f.add();// 調用自身 方法
F s = new S();
s.add();// 調用 重寫 方法
s.add3();// 調用 父類 方法
}
class F{
void add(){
System.out.println("父類add方法");
}
protected void add2(){
System.out.println("父類add2方法");
}
public void add3(){
System.out.println("父類add3方法");
}
}
class S extends F{
public void add(){// 重寫 時 通路權限 應 大于等于 父類
System.out.println("子類add2方法");
}
protected void add2(){
System.out.println("子類add2方法");
}
}
重載和重寫的差別;
override(重寫)
1、方法名、參數、傳回值相同。
2、子類方法不能縮小父類方法的通路權限。
3、子類方法不能抛出比父類方法更多的異常(但子類方法可以不抛出異常)。
4、存在于父類和子類之間。
5、方法被定義為final不能被重寫。
overload(重載)
1、參數類型、個數、順序至少有一個不相同。
2、不能重載隻有傳回值不同的方法名。
3、存在于父類和子類、同類中。
對于重寫的一點深入探讨
先上代碼:
public class Base {
private String baseName= "base";
public Base(){
callName();
}
public void callName(){
System.out.println(baseName);
}
static class Sub extends Base{
private String baseName = "sub";
public void callName(){
System.out.println(baseName);
}
}
public static void main(String[] args){
Base b = new Sub();
}
}
上述代碼輸出時什麼?
分析:
1.首先,看結構,一個外部類,一個靜态内部類,靜态内部類繼承了外部類,最後一個main方法測試。
2.我們看,main方法中 Base b = new Sub(); 父類變量 指向了 子類的引用,那麼明顯的,在方法中調用的是 子類的callName 方法。
這裡我們要清楚調用順序:
new Sub() 時 是先建立 父類對象,再去建立 子類對象,即,先會調用 父類的構造器,則會調用 callName() 方法,而 該方法 被 子類重寫,則會調用 子類的callName() 方法,但是,此時 子類還沒有構造,那麼 這裡的 baseName 就是 一個 null 值;
3.
執行 Base b = new Sub();時,由于多态 b編譯時表現為Base類特性,運作時表現為Sub類特性,Base b = new Sub();不管是哪種狀态都會調用Base構造器執行 callName()方法;執行方法時,由于多态表現為子類特性,是以會先在子類是否有 callName();而此時子類尚未初始化(執行完父類構造器後才會開始執行子類),如果有 就 執行(此時,因為還沒有調用子類構造函數, 是以子類的 baseName 輸出為 null),沒有再去父類尋找。
如果是這樣的:
public static void main(String[] args){
Base b = new Sub();
b.callName();
}
則會輸出 :
null
sub
總的來說: