簡體   English   中英

Java不一致的繼承機制?

[英]Java inconsistent inheritance mechanics?

我想我們已經在這篇文章中討論了這個問題,這里繼承Java簡單說明

但由於這里的例子有點簡單,我想澄清的意思不同,我會試一試。

首先,討論兩個類:

public class SuperClass{
    SuperClass() {
        foo();
    }

    public void foo() {
        System.out.println("Super.foo()");
    }

    public static void main(String[] args) {
            SuperClass tn = new DerivedClass();
            tn.foo();
    }
}

public class DerivedClass extends SuperClass{
    String i;

    TrickyB() {
        i = "aksjhdf";
    }

    public void foo() {
        System.out.println("In derived.foo() --> " + i);
    }
}

我(至少我認為)理解多態的概念,我知道為什么在調用時調用DerivedClass.foo()

new DerivedClass();

我在這看到一個不一致的地方:

在我們調用DerivedClass的DerivedClass ,SuperClass的SuperClass被隱式調用(所以說作為Derived c'tor的第一行)。

所以在Super c'tor中, DerivedClass沒有完全初始化,這使得使用這個類沒用。 這一點反映在該計划的輸出中

In derived.foo() --> null
In derived.foo() --> aksjhdf

第一行反映了我的困惑:

為什么調用DerivedClass.foo() 對象還沒有准備好,所以用它做任何事情在我眼里都是胡說八道。

任何人都可以向我解釋原因。 我認為這絕對違反直覺。

順便說一下:我SuperClass.foo()應該調用SuperClass.foo() ,因為正如我所說,使用“未准備”對象沒有任何意義。

另一方面:我想起來了。 這對我來說沒有任何意義,當我在SuperClass的時候, DerivedClass.foo()被調用!

在我的情況下,我如何調用SuperClass.foo()

為什么調用DerivedClass.foo()? 對象還沒有准備好,所以用它做任何事情在我眼里都是胡說八道。

沒有。該對象已經創建。 構造函數不創建對象,只是初始化它們。 該對象由new運算符在此創建。

我原以為要調用SuperClass.foo()

正如已經解釋過的那樣,並不是沒有創建對象。 它已經存在了。 並且該調用將調用重寫的方法。 這就是為什么你永遠不應該從構造函數調用重寫方法 你會看到意想不到的行為。

SuperClass對任何派生類都一無所知。

嗯,它不需要知道。 方法調用調用派生類方法的事實與超類是否知道子類無關。 將在運行時根據圖片中的實際對象確定將調用的實際方法。 因為在這里,對象的類型是DerivedClass ,在該方法DerivedClass如果存在的話將被調用。

在我的情況下,我如何調用SuperClass.foo()?

你沒有。 這就是重點。 瀏覽我鏈接的帖子,逐步解釋。

與C ++不同,Java在分配時,在運行任何構造函數之前設置對象的運行時類型。 這就是初始化期間發生多態行為的原因。

在受控情況下,此行為有時很有用。 但是,在大多數情況下,避免使用它是一個好主意,因為您正在將未初始化的對象泄露給類外部的代碼(通過虛方法中的this引用)。 您應盡可能嘗試從構造函數中調用私有(或最終)方法。

Why is DerivedClass.foo() called?

因為這是Java語言設計。 開發人員可以自己確保繼承層次結構中的不變類,而不是語言。

How would I call SuperClass.foo() in my case?

從派生類: super.foo();

DerivedClass.foo()在DerivedClass中調用。 為對象本身調用foo()。 通過繼承,這也可以等於SuperClass.foo()。 但是,由於多態性也可能不同。 如果你明確地想要來自SuperClass的foo(),那么調用super.foo()。 順便說一下,因為DerivedClass.foo()依賴於i,所以你應該首先初始化i。

正如Rohit所說,不應該從構造函數中調用重寫的方法(或更確切地說,可以覆蓋的方法)。 這是一個方法:

public class SuperClass{
    SuperClass() {
        privateFoo();
    }

    public void foo() {
        privateFoo();
    }

    private void privateFoo() {   // cannot be overridden since it's private
        System.out.println("Super.foo()");
    }

}

使foo方法只是一個調用私有版本的單行方法。 當然,如果它有參數和/或返回值,你可以包括那些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM