Java - 一文理解覆蓋和重載


  公眾號偶然看到的一個帖子,構造方法,類方法,final方法,哪些能覆蓋,哪些能重載,初學時也是被這些術語搞的很迷糊

現在有時間了對這些做一個總結。全是自己的語言,可能不是很全面,表達意思應該夠清楚

一、叫法

  • 構造方法

  又叫構造器,構造函數。通常有無參構造器和帶參數的構造器2種,每個類都有一個構造方法(如果沒有顯式的給出來,

那么也有一個默認的無參構造器)無返回類型修飾符。訪問修飾符可以是public,也可以是private,比如常見的單例模式就要求構

造函數私有化。

  • 類方法

  static修飾符修飾的方法。因為static修飾的方法是屬於類的而不是屬於實例的(這個描述各種書籍上非常常見),因此不必

去new 一個實例來調用,而是直接類名.方法名來調用這種方法,因此也稱為類方法。

  • final方法

  最終的、不可改變的、終極的方法。怎么叫都行,單詞修飾很清楚了,用了final表明設計上不再會去修改他,很巧,一

個叫abstract的修飾符就是要設計者去實現去重寫的,因此可以知道final和abstract永遠不能共存。

  • 覆蓋

  又叫重寫,Override。多態是java的特性,覆蓋是表現多態特性的具體做法。《Effective Java》有一個章節特別提出了,如

果是覆蓋方法,請一定記得加上@Override,在接下來的代碼描述中你會看到,很多種方法混雜在一起的時候看起來是多么的難受

  • 重載

  重載只發生在一個類中,記住這點很重要,這也是跟覆蓋這個概念撇清關系的最重要一點。重載要求同一個類中方法名相同

而參數列表不同。參數列表,就是入參的個數,類型,順序。抓住定義中的這兩點,其他的通過什么返回值,訪問權限,異常來重

載一個方法那就是扯淡,混淆,不行。

二、行還是不行?

建議直接拷貝類到你的idea中去理解!重要的提示都加了注釋

首先看下重載。最經典最常見的莫過於這兩個例子:構造方法的重載和System.out.println()這個方法了。我們直接看代碼:

public abstract class ClassTest {

    private int a;

    /**
     * abstract 和 final不能共存,報錯
     */
    abstract final void test();

    /**
     * 構造方法
     */
    public ClassTest() {
        System.out.println("調用父類無參構造方法");
    }

    /**
     * 構造方法重載為帶參的構造器
     */
    public ClassTest(int a) {
        this.a = a;
        System.out.println("調用重載的帶參構造方法");
        System.out.println(this.a);
    }

    /**
     * 類方法(靜態方法)
     */
    public static void staticMethod() {
        System.out.println("調用父類static方法(類方法)");
    }

    /**
     * 類方法可以被重載
     */
    public static void staticMethod(String s) {
        System.out.println("調用重載的類方法,s=" + s);
    }

    /**
     * final方法
     */
    public final void finalMethod() {
        System.out.println("調用父類final方法");
    }

    /**
     * final方法可以被重載
     */
    public final void finalMethod(String s) {
        System.out.println("調用重載的final方法,s=" + s);
    }

}

寫一個客戶端調用一下:

public class Client {
    public static void main(String[] args) {
        ClassTest.staticMethod();
        ClassTest.staticMethod("hello");
    }
}

我們得出如下結論:構造方法,類方法,final方法均可以被重載

接着我們看下覆蓋的情況:

還是用之前的定義的類,不過我們加入了一些別的情況:父類private的final方法和private的方法

public class ClassTest {

    /**
     * 構造方法
     */
    public ClassTest() {
        System.out.println("調用父類無參構造方法");
    }

    /**
     * 類方法(靜態方法)
     */
    public static void staticMethod() {
        System.out.println("調用父類static方法(類方法)");
    }

    /**
     * final方法
     */
    private final void finalMethod0() {
        System.out.println("調用父類private final方法");
    }

    /**
     * final方法
     */
    public final void finalMethod() {
        System.out.println("調用父類public final方法");
    }

    /**
     * 普通的私有方法
     */
    private void privateMethod() {
    System.out.println("調用父類public final方法");
}
}

子類是:

public class SubClassTest extends ClassTest {

    /**
     * 報錯提示:父類構造器不可覆蓋
     */
    @Override
    public ClassTest() {
        System.out.println("覆蓋父類構造方法");
    }

    /**
     * 報錯提示:父類的靜態方法不能覆蓋
     */
    @Override
    public static void staticMethod() {
        System.out.println("覆蓋父類靜態方法");
    }

    /**
     * 上面的@Override去掉,不再報錯
     * 說明這個方法只是和父類的靜態方法同名了而已,他是子類獨有的,與父類的沒半毛錢關系
     * 如果決定覆蓋,請敲上@Override,一般做項目也不會像我這樣測這些奇怪的情況,所以不加也知道是覆蓋了,但是還是請加上
     */
    public static void staticMethod() {
        System.out.println("子類的同名方法");
    }

    /**
     * 報錯提示:final方法不能被覆蓋
     */
//    @Override
//    public final void finalMethod() {
//        System.out.println("覆蓋final方法");
//    }

    /**
     * 未加@Override
     * 錯誤提示:final方法不能覆蓋
     * 說明子類的final方法連名字都不能跟父類的同名,否則認為是覆蓋
     */
    public final void finalMethod() {
        System.out.println("覆蓋final方法");
    }

    /**
     * 未加@Override
     * 父類中該方法是private final的
     * 子類可以擁有對應的public權限的final同名方法
     */
    public final void finalMethod0() {
        System.out.println("調用子類同名的final方法");
    }

    /**
     * 錯誤提示:父類私有方法不能被覆蓋
     */
    @Override
    public void privateMethod() {
        System.out.println("調用普通的private方法");
    }

}

編譯結果我在注釋里都寫了,我們可以得出:構造方法,類方法,final方法都不能覆蓋

注意:

  1、子類可以擁有和父類同名的static方法,參看上面的staticMethod方法的注釋,這個方法和父類的那個沒半毛錢關系

  2、父類的public final方法,子類不能覆蓋,也不能有自己的同樣的方法(這就是我為啥,effective java也,強調加上@Override的原因)

  3、父類的private final方法,子類可以有對應的public final的,但是也和父類對應的這個方法沒半毛錢關系,只是語法上允許

注意:

  以上的類直接復制在開發工具上會報錯的,這也是我們想要的

三、為什么不行?從意義和設計上窺探下

  static方法為什么不能被覆蓋,我們試着從意義上理解下,static是類的不是實例的,意味着它是無狀態的,而覆蓋發生在多態中,也就是

每個實例各自去show,從java運行角度講,static的方法在編譯時就綁定完了,而多態要在運行時才確定,該調用誰覆蓋后的方法。

  final方法為什么不能覆蓋,設計final關鍵字的意義是,開發者知道這個方法一旦完成,就不打算再修改它,子類如果需要,可以直接調用

如果各個子類也去覆蓋這個final方法,那父類的這個方法再用final修飾就沒啥意義了

  最后private修飾的方法會被隱形的指定為final的,所以也不能覆蓋,這個可以在Thinking in Java中找到

 

以上是個人一些小總結,不到之處,還請指正~~ 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM