2010-09-09 78 views
7

示例1:爲什麼這兩個代碼樣本產生不同的輸出?

class Animal { 
    public static void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public static void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

輸出是:

Gurrr! Gurrr! Moo! 

示例2:

class Animal { 
    public void saySomething() { System.out.print(" Gurrr!"); 
    } 
} 
class Cow extends Animal { 
    public void saySomething() { 
    System.out.print(" Moo!"); 
    } 
    public static void main(String [] args) { 
     Animal [] animals = {new Animal(), new Cow()}; 
     for(Animal a : animals) { 
      a.saySomething(); 
     } 
     new Cow().saySomething(); 
    } 
} 

輸出:

Gurrr! Moo! Moo! 

我只是不明白爲什麼做saySomething非統計ic導致第二次調用saySomething調用Cow版本而不是Animal版本。我的理解是Gurrr! Moo! Moo!是兩種情況下的輸出。

+0

「Java語言規範說得那麼簡單」實際上就是這樣。爲什麼你被允許從一個實例引用中調用一個靜態方法,就像真正的奇怪一樣。但是至少有一個巨大的社區維基線程:) – Affe 2010-09-09 19:55:32

回答

1

靜態方法在編譯時綁定到它們的類並且不能多態使用。當你在Animal上聲明一個「靜態」方法時,它永遠與Animal類綁定,不能被覆蓋。靜態方法綁定到Class對象,而不是Class的實例。

常規方法在運行時綁定,因此JVM可以查看您對「saySomething」的調用並嘗試確定是否傳遞給Animal的子類,如果是,它是否覆蓋了方法saySomething()。常規方法綁定到對象的實例,而不是綁定到類本身。

這也是爲什麼你永遠無法做到這一點:

class Animal 
{ 
    public abstract static void saySomething(); 
} 

由於「靜態」的意思是「在編譯時綁定」,是沒有意義的東西是靜態和抽象。

7

當您對動物致電saySomething()時,動物的實際類型不計數,因爲saySomething()是靜態的。

Animal cow = new Cow(); 
cow.saySomething(); 

相同

Animal.saySomething(); 

甲JLS例如:

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

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

}

它打印:
諾納德諾克山
這裏最喜歡返回null,但沒有拋出NullPointerException。


資源:

關於同一主題:

+1

我從來沒有理解爲什麼Java允許通過對象引用來調用靜態方法。這是沒有必要的,而且會導致這樣的混亂。 – erickson 2010-09-09 19:53:55

+0

同意。 C++也可以讓你做到這一點。我的猜測是,只是讓編譯器編寫者容易進行這種訪問。 – 2010-09-09 19:57:35

+0

那麼,我試圖在這裏辯護:http://stackoverflow.com/questions/3610309/java-static-confusion/ – 2010-09-09 20:07:05

3

你不能覆蓋與子類相同的簽名,只是隱藏他們的靜態方法。

對於類的方法,運行時系統調用在其上該方法被稱爲參考的編譯時類型定義的方法。對於實例方法,運行時系統調用在其中調用該方法的參考運行時類型中定義的方法。

http://life.csu.edu.au/java-tut/java/javaOO/override.html

3

一些已知的重寫 「缺陷」 一

  • 靜態方法不能被重寫
  • 私有方法不能被重寫

這解釋了輸出。

1

靜態方法綁定到「類」,而不是對象的「實例」。 由於您指的是「動物」並調用了靜態方法saySomething()。除非你指的是母牛,否則它總是會打電話給「動物」。

相關問題