2013-02-12 224 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

相关问题