1. 程式人生 > >java 重寫(override) 和 過載(overload) 的實現原理

java 重寫(override) 和 過載(overload) 的實現原理

    剛開始學習Java的時候,就瞭解了Java這個比較有意思的特性:重寫 和 過載。開始的有時候從名字上還總是容易弄混。我相信熟悉Java這門語言的同學都應該瞭解這兩個特性,可能只是從語言層面上了解這種寫法,但是jvm是如何實現他們的呢,並不是很清楚。

過載官方給出的介紹:

一.  overload:

The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists .

Overloaded methods are differentiated by the number and the type of the arguments passed into the method.

You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.

The compiler does not consider return type when differentiating methods, so you cannot declare two methods with the same signature even if they have a different return type.

首先看一段程式碼,來看看程式碼的執行結果:

public class OverrideTest {

    class Father{}

    class Sun extends Father {}

    public void doSomething(Father father){
        System.out.println("Father do something");
    }

    public void doSomething(Sun father){
        System.out.println("Sun do something");
    }

    public static void main(String [] args){
        OverrideTest overrideTest = new OverrideTest();
        Father sun = overrideTest.new Sun();
        Father father = overrideTest.new Father();
        overrideTest.doSomething(father);
        overrideTest.doSomething(sun);
    }
}

看下這段程式碼的執行結果,最後會列印:

Father do something Father do something

為什麼會打印出這樣的結果呢? 首先要介紹兩個概念:靜態分派和動態分派

靜態分派:依賴靜態型別來定位方法執行版本的分派動作稱為靜態分派

動態分派:執行期根據實際型別確定方法執行版本的分派過程。

他們的區別是:

1.  靜態分派發生在編譯期,動態分派發生在執行期;

2.  private,static,final 方法發生在編譯期,並且不能被重寫,一旦發生了重寫,將會在執行期處理。

3.  過載是靜態分派,重寫是動態分派

回到上面的問題,因為過載是發生在編譯期,所以在編譯期已經確定兩次 doSomething 方法的引數都是Father型別,在class檔案中已經指向了Father類的符號引用,所以最後會列印兩次Father do something。

二. override:

An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method.

The ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed. The overriding method has the same name, number and type of parameters, and return type as the method that it overrides. An overriding method can also return a subtype of the type returned by the overridden method. This subtype is called a covariant return type.

還是上面那個程式碼,稍微改動下

public class OverrideTest {

    class Father{}

    class Sun extends Father {}

    public void doSomething(){
        System.out.println("Father do something");
    }

    public void doSomething(){
        System.out.println("Sun do something");
    }

    public static void main(String [] args){
        OverrideTest overrideTest = new OverrideTest();
        Father sun = overrideTest.new Sun();
        Father father = overrideTest.new Father();
        overrideTest.doSomething();
        overrideTest.doSomething();
    }
}

​

最後會列印:

Father do something

Sun do something

相信大家都會知道這個結果,那麼這個結果jvm是怎麼實現的呢?

在編譯期,只會識別到是呼叫Father類的doSomething方法,到執行期才會真正找到物件的實際型別。

首先該方法的執行,jvm會呼叫invokevirtual指令,該指令會找棧頂第一個元素所指向的物件的實際型別,如果該型別存在呼叫的方法,則會走驗證流程,否則繼續找其父類。這也是為什麼子類可以直接呼叫父類具有訪問許可權的方法的原因。簡而言之,就是在執行期才會去確定物件的實際型別,根據這個實際型別確定方法執行版本,這個過程稱為動態分派。override 的實現依賴jvm的動態分派。