aru*_*rul 41
Anders Hejlsberg :( C#首席架构师)
有几个原因.一个是表现.我们可以观察到,当人们用Java编写代码时,他们忘记了最终标记他们的方法.因此,这些方法是虚拟的.因为它们是虚拟的,所以它们表现不佳.与虚拟方法相关的只是性能开销.这是一个问题.
版本控制更重要的一个问题.虚拟方法有两种思想流派.思想学院说,"一切都应该是虚拟的,因为有一天我可能想要覆盖它." 实用主义思想源于构建在现实世界中运行的真实应用程序,他说:"我们必须真正关注我们虚拟化的东西."
当我们在一个平台上制作虚拟东西时,我们会对未来的演变做出很多承诺.对于非虚方法,我们保证当您调用此方法时,将发生x和y.当我们在API中发布虚拟方法时,我们不仅承诺当您调用此方法时,x和y将会发生.我们还承诺,当你重写这个方法时,我们将按照这个特定的顺序对它们进行调用,并且状态将在这个和那个不变量中.
每当你在API中说虚拟时,你就是在创建一个回调钩子.作为操作系统或API框架设计师,您必须非常小心.您不希望用户在API中的任意点上覆盖和挂钩,因为您不一定能够做出这些承诺.人们可能无法完全理解他们在做虚拟事物时所做的承诺.
Java的方式更简单,默认情况下,C#的方式更精细,更安全,更高效.哪个更好的是在啤酒持有人的眼中.
默认情况下虚拟比非虚拟好得多有两个主要原因。
在 Java 中,如果将 ClassB 定义为
public class ClassB extends ClassA {
@Override
public void run() {
}
}
Run Code Online (Sandbox Code Playgroud)
和对象
ClassA obj=new ClassB();
Run Code Online (Sandbox Code Playgroud)
如果您调用 obj.run(),您如何知道该代码是否遵循多态打开/关闭原则的规则,或者它将编码与 ClassA 相关的方法?在Java中你会知道多态总是存在的。更容易进行模拟,更容易扩展类并遵循里氏替换原则。
另一方面,静态方法绑定到类,因此如果您想调用与 ClassA 相关的方法,您可以像这样定义该方法:
public static run(ClassA obj)
Run Code Online (Sandbox Code Playgroud)
你可以用它来调用它
ClassB obj=new ClassB();
ClassA.run(obj);
Run Code Online (Sandbox Code Playgroud)
从代码中你会知道你调用的方法是在ClassA中定义的,而不是在ClassB中定义的。同样在这种情况下,您将不会有虚拟方法的开销。(请注意,在许多情况下,JIT 还会减少虚拟方法的开销)。
对于 C#,如果使方法成为非虚拟方法的原因是能够在子类中定义它但不涉及多态性,那么您可能没有真正的理由进行子类化。
如果是为了设计,我建议如果可能的话,将类密封(java中的final)而不是单独的方法。
Jon Skeet 说,在 C# 中,默认情况下类应该是密封的,因为默认情况下方法也是非虚拟的。Joshua Bloch 说,你应该为继承而设计,或者禁止它(使类成为最终的)。C# 设计者选择了一种不一致的混合方法。