2013-02-12 230 views
18

我被告知static方法隱含地爲final,因此不能被覆蓋。真的嗎?C#中可以重寫一個靜態方法嗎?

  1. 有人可以提供一個更好的例子,覆蓋靜態方法嗎?

  2. 如果靜態方法只是類方法,那麼它們的真正用處是什麼?

+1

不,它們不能被覆蓋。他們與班級相關,而不是與對象相關聯。 – 2013-02-12 08:23:13

+0

供實際使用:您可以調用不帶類實例的靜態方法。 – Najzero 2013-02-12 08:23:54

+0

謝謝。我明白[靜態方法是什麼](http://stackoverflow.com/a/4124118/2061309),SLak提供了最好的例子。所以對於我的問題重寫一個靜態方法(如果bydefault是最終的,而不是用戶使其最終) - 這是否意味着沒有這個類的子類,它擁有一個靜態可以定義一個靜態方法具有相同的簽名? – aspiring 2013-02-12 08:28:54

回答

17

(1)靜態方法不能被覆蓋,但可以使用'new'關鍵字隱藏。大多數重寫方法意味着你引用一個基類型並想調用派生方法。由於靜態是類型的一部分,並且不受vtable查找的影響。

E.g.靜不能做:

public class Foo { 
    public virtual void Bar() { ... } 
} 
public class Bar : Foo { 
    public override void Bar() { ... } 
} 

// use: 
Foo foo = new Bar(); // make an instance 
foo.Bar(); // calls Bar::Bar 

由於靜不上情況下工作,你總是指定Foo.Bar或Bar.Bar明確。因此,重寫在這裏沒有意義(嘗試在代碼中表達它...)。

(2)靜態方法有不同的用法。例如,它在Singleton模式中被用來獲取一個類型的單個實例。另一個例子是'static void Main',它是程序中的主要訪問點。

基本上,只要你不想使用它們,或者在使用它之前不能創建對象實例。例如,當靜態方法創建該對象時。

[更新]

一個簡單的隱藏例如:

public class StaticTest 
{ 
    public static void Foo() { Console.WriteLine("Foo 1"); } 
    public static void Bar() { Console.WriteLine("Bar 1"); } 
} 

public class StaticTest2 : StaticTest 
{ 
    public new static void Foo() { Console.WriteLine("Foo 2"); } 
    public static void Some() { Foo(); Bar(); } // Will print Foo 2, Bar 1 
} 

public class TestStatic 
{ 
    static void Main(string[] args) 
    { 
     StaticTest2.Foo(); 
     StaticTest2.Some(); 
     StaticTest.Foo(); 
     Console.ReadLine(); 
    } 
} 

請注意,如果你做的類static,你不能做到這一點。靜態類必須從object派生。

這個和繼承之間的主要區別是編譯器可以在編譯時確定使用靜態時要調用哪個方法。如果您有對象的實例,則需要在運行時執行此操作(稱爲vtable查找)。

+0

謝謝你給我重寫的例子。是的,我嘗試了代碼。所以爲了做到這一點,1)**我們可以像任何其他非靜態類一樣爲子類靜態類**嗎? 2)我們可以使用靜態方法而不用重寫父類的靜態方法,但使用New關鍵字隱藏它們。 – aspiring 2013-02-12 09:40:45

+0

我加了一些解釋和例子。 (1)不,你不能分類靜態類,但你可以隱藏靜態成員。 (2)是的,你應該嘗試第二個例子,它告訴它如何表現。 – atlaste 2013-02-12 10:11:45

+3

什麼時候這個Foo <->酒吧廢話結束???停止使用FoorBar作爲示例,在每種情況下,Bar和Foo都是類或子類或函數或方法。所以點什麼?只需使用動物進行子類化和重寫操作即可。 10x – 2014-10-27 16:59:31

5

您不重寫靜態方法。你隱藏它。有關更多信息,請參閱this answer

的部分原因是使用靜態方法:

  1. 他們是一個比little bit faster實例方法。另請參閱此msdn article,其中提供了性能數字以支持此功能(內聯靜態呼叫平均值爲0.2 ns,靜態呼叫平均值爲6.1ns,內聯實例呼叫平均值爲1.1 ns,實例呼叫平均值爲6.8 ns)
  2. 不詳細寫出 - t需要實例化一個類以獲得它們(並且實例化也可以影響性能)
+0

我對實例方法沒有任何問題。我瞭解到'static'類不能被實例化。但是你提到「靜態方法是它只在你的應用中實例化了一次」。所以我現在很困惑。你是指'使用System.Math;'通過說靜態方法被實例化?我一直在同一個類中多次使用Math類成員Math.Abs​​(),而沒有將它們實例化一次。 1)那麼你能否請你澄清你的意思***「實例化一次」***? 2)靜態類可以是子類嗎?子類靜態類是否有意義? – aspiring 2013-02-12 08:53:58

+1

看到我的編輯。我不應該用靜態方法使用術語「實例化」。更正確的是說它只創建一次。 – 2013-02-12 09:03:06

+1

所有*方法*僅「創建」一次。即使非靜態方法也只有一個代碼副本(在編譯時創建的IL代碼,在運行時一次*轉換爲機器代碼)。不要混淆代碼和數據!一個非靜態方法只能通過一個對象的實例被調用,但這是因爲隱藏的「this」指針被傳遞給它。代碼本身是「靜態的」,因爲它是固定的和單例的。 – 2013-02-12 09:12:13

5

那麼你不能覆蓋靜態方法。靜態方法不能是虛擬的,因爲它與類的實例無關。

派生類中的「overriden」方法實際上是一種新方法,與基類中定義的方法無關(因此與new關鍵字無關)。 (從純OOP的觀點來看),這是一個很重要的事情要理解:當類型從其他類型繼承,它們履行一個公共契約,而靜態類型不受任何契約約束。在語言中沒有技術方法將兩種靜態類型與「繼承」合同綁定在一起。如果你想在兩個不同的地方「覆蓋」Log方法。

如果您考慮過度使用靜態方法,它並沒有什麼意義;爲了有虛擬調度,你需要一個對象的實際實例來檢查。

靜態方法也不能實現接口;如果這個類正在實現IRolesService接口,那麼我會爭辯說該方法不應該是靜態的。具有實例方法的設計更好,因此您可以在準備就緒時用真實服務替換MockRoleService

+0

謝謝。這對我來說有點兒消化,但是一路上我會明白的:) PS:在那種情況下,我絕對想在你的課堂上。發現[這篇文章也在Java上下文中。](http://www.xyzws.com/Javafaq/can-static-methods-be-overridden/1) – aspiring 2013-02-12 09:02:10

+1

呵呵,甚至我也學習c#..我22歲老,在公司工作..通過簡單的事情你會一步一步地得到它。 – Neel 2013-02-12 09:04:39

相關問題