方法重寫java
class Animal { public void eat(){ System.out.println ("Animal is eating."); } } class Horse extends Animal{ public void eat(){ System.out.println ("Horse is eating."); } }
public class Test { public static void main (String[] args) { Animal h = new Horse(); h.eat(); } } class Animal { public void eat(){ System.out.println ("Animal is eating."); } } class Horse extends Animal{ public void eat(){ System.out.println ("Horse is eating."); } public void buck(){ } }
import java.io.*; public class Test { public static void main (String[] args) { Animal h = new Horse(); try { h.eat(); } catch (Exception e) { } } } class Animal { public void eat() throws Exception{ System.out.println ("Animal is eating."); throw new Exception(); } } class Horse extends Animal{ public void eat() throws IOException{ System.out.println ("Horse is eating."); throw new IOException(); } }
public class Test { public static void main (String[] args) { //Animal h = new Horse(); Horse h = new Horse(); h.eat(); } } class Animal { private void eat(){ System.out.println ("Animal is eating."); } } class Horse extends Animal{ public void eat(){ System.out.println ("Horse is eating."); } }
Animal h = new Horse(); //Horse h = new Horse(); h.eat();
方法的重載編程
重載是友好的,它不要求你在調用一個方法以前轉換數據類型,它會自動地尋找匹配的方法。方法的重載是在編譯時刻就決定調用哪一個方法了,和重寫不一樣。最最經常使用的地方就是構造器的重載。
一、基本數據類型參數的重載。app
public class Test { static void method(byte b){ System.out.println ("method:byte"); } static void method(short s){ System.out.println ("method:short"); } static void method(int i){ System.out.println ("method:int"); } static void method(float f){ System.out.println ("method:float"); } static void method(double d){ System.out.println ("method:double"); } public static void main (String[] args) { method((byte)1); method('c'); method(1); method(1L); method(1.1); method(1.1f); } }
輸出結果:函數
method:byte method:int method:int method:float method:double method:float
能夠看出:首先要尋找的是數據類型正好匹配方法。若是找不到,那麼就提高爲表達能力更強的數據類型,如上例沒有正好容納long的整數類型,那麼就轉換爲 float類型的。若是經過提高也不能找到合適的兼容類型,那麼編譯器就會報錯。反正是不會自動轉換爲較小的數據類型的,必須本身強制轉換,本身來承擔轉變後果。
char類型比較特殊,若是找不到正好匹配的類型,它會轉化爲int而不是short,雖然char是16位的。
二、重載方法的規則。
A、被重載的方法必須改變參數列表。
參數必須不一樣,這是最重要的!不一樣有兩個方面,參數的個數,參數的類型,參數的順序。
B、被重載的方法與返回類型無關。
也就是說,不能經過返回類型來區分重載方法。
C、被重載的方法能夠改變訪問修飾符。
沒有重寫方法那樣嚴格的限制。
D、被重載的方法能夠聲明新的或者更廣的檢查異常。
沒有重寫方法那樣嚴格的限制。
E、方法可以在一個類中或者在一個子類中被重載。
三、帶對象引用參數的方法重載。this
class Animal {} class Horse extends Animal{} public class Test { static void method(Animal a){ System.out.println ("Animal is called."); } static void method(Horse h){ System.out.println ("Horse is called."); } public static void main (String[] args) { Animal a = new Animal(); Horse h = new Horse(); Animal ah = new Horse(); method(a); method(h); method(ah); } }
輸出結果是:編碼
Animal is called.
Horse is called.
Animal is called.
前兩個輸出沒有任何問題。第三個方法爲何不是輸出「Horse is called.」呢?仍是那句老話,要看引用類型而不是對象類型,方法重載是在編譯時刻就決定的了,引用類型決定了調用哪一個版本的重載方法。
四、重載和重寫方法區別的小結。
若是能完全弄明白下面的例子,說明你對重載和重寫很是瞭解了,能夠結束這節的複習了。spa
class Animal { public void eat(){ System.out.println ("Animal is eating."); } } class Horse extends Animal{ public void eat(){ System.out.println ("Horse is eating."); } public void eat(String food){ System.out.println ("Horse is eating " + food); } } public class Test { public static void main (String[] args) { Animal a = new Animal(); Horse h = new Horse(); Animal ah = new Horse(); a.eat(); h.eat(); h.eat("apple"); ah.eat(); //a.eat("apple"); //ah.eat("apple"); } }
四個輸出分別是什麼?被註釋的兩條語句爲何不能經過編譯?
第一條:a.eat(); 普通的方法調用,沒有多態,沒什麼技術含量。調用了Animal類的eat()方法,輸出:Animal is eating.
第二條:h.eat(); 普通的方法調用,也沒什麼技術含量。調用了Horse類的eat()方法,輸出:Horse is eating.
第三條:h.eat("apple"); 重載。Horse類的兩個eat()方法重載。調用了Horse類的eat(String food)方法,輸出:Horse is eating apple
第四條:ah.eat(); 多態。前面有例子了,不難理解。輸出:Horse is eating.
第五條:a.eat("apple"); 低級的錯誤,Animal類中沒有eat(String food)方法。所以不能經過編譯。
第六條:ah.eat("apple"); 關鍵點就在這裏。解決的方法仍是那句老話,不能看對象類型,要看引用類型。Animal類中沒有eat(String food)方法。所以不能經過編譯。
小結一下:多態不決定調用哪一個重載版本;多態只有在決定哪一個重寫版本時才起做用。
重載對應編譯時,重寫對應運行時。夠簡潔的了吧!
設計
構造方法code
構造方法是一種特殊的方法,沒有構造方法就不能建立一個新對象。實際上,不只要調用對象實際類型的構造方法,還要調用其父類的構造方法,向上追溯,直到 Object類。構造方法沒必要顯式地調用,當使用new關鍵字時,相應的構造方法會自動被調用。
一、構造方法的規則。
A、構造方法能使用任何訪問修飾符。包括private,事實上java類庫有不少都是這樣的,設計者不但願使用者建立該類的對象。
B、構造方法的名稱必須與類名相同。這樣使得構造方法不同凡響,若是咱們遵照sun的編碼規範,彷佛只有構造方法的首字母是大寫的。
C、構造方法不能有返回類型。
反過來講,有返回類型的不是構造方法對象
public class Test { int Test(){ return 1; } }
這個方法是什麼東西?一個冒充李逵的李鬼而已,int Test()和其餘任何普通方法沒什麼兩樣,就是普通的方法!只不過看起來很噁心,相似噁心的東西在考試卷子裏比較多。
D、如果不在類中建立本身的構造方法,編譯器會自動生成默認的不帶參數的構造函數。
這點很容易驗證!寫一個這樣簡單的類,編譯。
class Test { }
對生成的Test.class文件反編譯:javap Test,能夠看到:
D:"JavaCode"bin>javap Test Compiled from "Test.java" class Test extends java.lang.Object{ Test(); }
看到編譯器自動添加的默認構造函數了吧!
E、若是隻建立了帶參數的構造方法,那麼編譯器不會自動添加無參的構造方法的!
F、在每一個構造方法中,若是使用了重載構造函數this()方法,或者父類的構造方法super()方法,那麼this()方法或者super()方法必須放在第一行。並且這兩個方法只能選擇一個,所以它們之間沒有順序問題。
G、除了編譯器生成的構造方法,並且沒有顯式地調用super()方法,那麼編譯器會插入一個super()無參調用。
H、抽象類有構造方法。
靜態方法的重載與重寫(覆蓋)
一、靜態方法是不能被覆蓋的。能夠分兩種狀況討論:
A、子類的非靜態方法「覆蓋」父類的靜態方法。
這種狀況下,是不能經過編譯的。
class Father{ static void print(){ System.out.println ( " in father method " ); } } class Child extends Father{ void print(){ System.out.println ( " in child method " ); } }
static方法表示該方法不關聯具體的類的對象,能夠經過類名直接調用,也就是編譯的前期就綁定了,不存在後期動態綁定,也就是不能實現多態。子類的非靜態方法是與具體的對象綁定的,二者有着不一樣的含義。
B、子類的靜態方法「覆蓋」父類靜態方法。
這個覆蓋依然是帶引號的。事實上把上面那個例子Child類的print方法前面加上static修飾符,確實能經過編譯!可是不要覺得這就是多態!多態的特色是動態綁定,看下面的例子:
class Father{ static void print(){ System.out.println ( " in father method " ); } } class Child extends Father{ static void print(){ System.out.println ( " in child method " ); } } class Test{ public static void main (String[] args) { Father f = new Child(); f.print(); } }
輸出結果是:in father method
從這個結果能夠看出,並無實現多態。
可是這種形式很迷惑人,貌似多態,實際編程中千萬不要這樣搞,會把你們搞懵的!
它不符合覆蓋表現出來的特性,不該該算是覆蓋!
總而言之,靜態方法不能被覆蓋。
二、靜態方法能夠和非靜態方法同樣被重載。
這樣的例子太多了,我不想寫例程了。看看java類庫中不少這樣的例子。
如java.util.Arrays類的一堆重載的binarySearch方法。
在這裏提一下是由於查資料時看到這樣的話「sun的SL275課程說,靜態方法只能控制靜態變量(他們自己沒有),靜態方法不能被重載和覆蓋……」
你們不要相信啊!能夠重載的。並且靜態與非靜態方法能夠重載。
從重載的機制很容易就理解了,重載是在編譯時刻就決定的了,非靜態方法均可以,靜態方法怎麼可能不會呢?
致謝:感謝您的耐心閱讀!