這篇文章來聊一聊方法過載和重寫到底是有什麼區別,過載實現的是編譯時多型,而方法重寫實現的是執行時多型,那什麼又是編譯時多型和執行時多型呢?
定義一個Animal類,
public class Animal {
public void say(int age){
System.out.println("我的年齡是" + age);
}
public void say(int age, int weight){
System.out.println("我的年齡是" + age + ", 體重是" + weight);
}
public void say(String name){
System.out.println("我的姓名是" + name);
}
}
這邊寫了3個say方法,同名方法為什麼可以同時存在,這邊就要說到過載的機制了。對方法而言只要引數列表不同,那麼就可以定義為同名方法,在編譯時編譯器會判斷要呼叫的到底是哪一個方法,這也就是編譯時多型。引數列表是什麼?引數列表就是方法括號後面那一串,只要引數個數或者型別不同,那麼就可以實現過載。注意:引數列表和返回型別沒有任何關係,哪怕返回型別是int,String或者其他型別,都不能改變引數列表,這邊是個容易理解錯的地方。
下面情況不屬於方法過載,而且編譯無法透過,會直接報錯
public class ParamsList {
public String display(String temp){
return "ABC";
}
public int display(String temp){
return 1024;
}
}
換個角度想想:你上面的方法傳一個String,下面的傳的也是String,誰知道你要幹嘛
?誰知道你要調哪個方法?
所以改變返回型別是無法實現過載的,所以它也不屬於引數列表的一部分。
測試一下剛才的Animal例子,
public class OverTest {
public static void main(String[] args) {
Animal animal = new Animal();
animal.say(18);
animal.say(24, 50);
animal.say("john");
}
}
得到的結果如下
我的年齡是18
我的年齡是24, 體重是50
我的姓名是john
可以看到方法的確都被正確的呼叫了,這邊就是實現方法過載的辦法。
那麼方法重寫呢?又是怎麼回事,下面定義一個圖形Shape類,包含圓形Circle和長方形Rectangle。圓形和長方形明顯是圖形的子類,圖形是抽象的,是一個概念,而圓形和長方形是具體的,有具體的規則約定。
Shape
public class Shape {
public void run(){
System.out.println("這是一個圖形");
}
}
Circle
public class Circle extends Shape{
@Override
public void run() {
System.out.println("這是一個圓形");
}
}
Rectangle
public class Rectangle extends Shape{
@Override
public void run() {
System.out.println("這是一個長方形");
}
}
Circle和Rectangle繼承了Shape類,並定義了run方法,子類定義了和父類同名並且引數相同的方法,這種行為就叫做方法重寫。在執行時會根據物件來判斷是需要呼叫哪一個方法,下面測試一下。
public class OverTest {
public static void main(String[] args) {
Shape shape = new Shape();
Shape circle = new Circle();
Shape rectangle = new Rectangle();
start(shape);
start(circle);
start(rectangle);
}
public static void start(Shape shape){
shape.run();
}
}
start方法會根據我們執行時建立的物件來判斷,到底呼叫哪一個run方法。測試結果如下
這是一個圖形
這是一個圓形
這是一個長方形
可以看到run方法都被正確呼叫,這就是實現執行時多型的流程。
方法重寫和方法過載有什麼用呢?
方法過載可以避免方法名因為不能衝突而思考怎麼定義一大堆同名方法的問題,更加便捷,同時也提升了程式碼可讀性,簡化程式碼。
方法重寫提高了程式碼的可擴充套件性,例如圖形其實是一個抽象的概念,可以把塔延伸為具體的圖形,比如圓形,長方形,但不止於此,還有三角形,多邊形... 例如在傳參時,可以把型別定義為Shape類,那麼呼叫的時候Shape本身和所有繼承自Shape的類都可以傳入,並自動識別需要呼叫的run方法。