2015-09-05 182 views
4

爲什麼有可能從子實例訪問我的超類的靜態方法?爲什麼我可以從子實例訪問我的超類的靜態方法?

public class Test { 

    public static void main(String[] args) { 
     new UtilImpl().fun(); 
     new AbstractUtil() {}.fun(); 
    } 

    static abstract class AbstractUtil { 
     public static void fun() { 
      System.out.println("Fun!"); 
     } 
    } 

    static class UtilImpl extends AbstractUtil { 
    } 

} 

我可以從父類的實例訪問父類的靜態方法達成一致。但是,如果我實例化一個子類,那麼訪問父類的靜態上下文就很奇怪。

PS

什麼是調用實例的靜態方法的優勢是什麼?

+3

爲什麼?因爲它是這樣指定的。但是,您會收到警告。 – Dici

+0

這個主題已經很好的涵蓋了,有例子和解釋,在這裏:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html –

+0

這個問題實際上並不乏味,檢查我關聯的SO問題 – Dici

回答

3

在Java中,允許使用實例變量調用靜態方法。這在JLS section 8.4.3.2中定義,引用爲:

被聲明爲靜態的方法稱爲類方法。

總是調用一個類方法而不參考特定的對象。

在這種情況下,Java實際上會放棄您使用的實例並調用靜態方法。

Example 15.12.4.1-1表示此以下面的方式:

當目標參考被計算,然後被丟棄,因爲 調用模式是靜態的,沒有檢查基準看 它是否爲空:

class Test1 { 
    static void mountain() { 
     System.out.println("Monadnock"); 
    } 
    static Test1 favorite(){ 
     System.out.print("Mount "); 
     return null; 
    } 
    public static void main(String[] args) { 
     favorite().mountain(); 
    } 
} 

它打印:

Mount Monadnock 

這裏favorite()返回null,但不拋出NullPointerException。

+0

這意味着編譯器會重寫要在'Class'單例權限上執行的調用?他們爲什麼允許這樣做? – Dici

+0

我寧願給這[鏈接](https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8) – Finkelson

+0

其實我知道規範。這裏最有趣的問題是Java創建者爲什麼做這個功能。 – Finkelson

3

它被稱爲繼承。子類繼承public父類的成員,包括static方法。重要的是static方法不綁定到任何實例。你可以這樣做:

UtilImpl.fun(); 
AbstractUtil.fun(); 

就編譯器而言,它是一回事。唯一的區別是你的代碼創建了對象,但是這些與方法調用的方式無關(另外@Dici在註釋中說你應該也從編譯器得到警告)。

+0

他也從實例中調用靜態方法,您可能需要在此上添加一些東西 – Dici

相關問題