47

我被告知static方法是隐式的final,因此不能被覆盖。真的吗?

  1. 有人可以举一个更好的覆盖静态方法的例子吗?

  2. 如果静态方法只是类方法,那么拥有它们的真正用途是什么?

4

3 回答 3

42

(1) 静态方法不能被覆盖,但是可以使用'new'关键字隐藏它们。大多数覆盖方法意味着您引用基类型并希望调用派生方法。由于静态是类型的一部分,并且不受没有意义的 vtable 查找的影响。

例如静态不能做:

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.

The main difference between this and inheritance is that the compiler can determine at compile-time which method to call when using static. If you have instances of objects, you need to do this at runtime (which is called a vtable lookup).

于 2013-02-12T08:30:10.560 回答
7

好吧,您不能覆盖静态方法。静态方法不能是虚拟的,因为它与类的实例无关。

派生类中的“重写”方法实际上是一种新方法,与基类中定义的方法无关(因此使用了 new 关键字)。

理解这一点很重要:当类型从其他类型继承时,它们履行一个共同的契约,而静态类型不受任何契约的约束(从纯 OOP 的角度来看)。语言中没有技术方法可以将两种静态类型与“继承”契约联系在一起。如果您要在两个不同的地方“覆盖” Log 方法。

如果您考虑覆盖静态方法,那真的没有意义;为了进行虚拟调度,您需要一个对象的实际实例来检查。

静态方法也不能实现接口;如果这个类正在实现一个 IRolesService 接口,那么我认为该方法根本不应该是静态的。拥有实例方法是更好的设计,因此您可以在准备好时将 MockRoleService 换成真实的服务

于 2013-02-12T08:27:08.487 回答
5

您不会覆盖静态方法。你把它藏起来。有关更多信息,请参阅此答案

使用静态方法的一些原因:

  1. 它们比实例方法快一点。另请参阅此msdn 文章,它提供了性能数据来支持这一点(内联静态调用平均值 0.2 ns,静态调用平均值 6.1ns,内联实例调用平均值 1.1 ns,实例调用平均值 6.8 ns)
  2. 写出来不那么冗长 - 不需要实例化一个类来获取它们(实例化也会影响性能)
于 2013-02-12T08:24:31.910 回答