为什么默认情况下Java中的方法是虚拟的,而C#中默认是非虚拟的?

SNA*_*SNA 17 c# java oop

在Java中,默认情况下方法是虚拟的; C#正好相反.

哪个更好?每种方法有哪些优缺点?

aru*_*rul 41

Anders Hejlsberg :( C#首席架构师)

有几个原因.一个是表现.我们可以观察到,当人们用Java编写代码时,他们忘记了最终标记他们的方法.因此,这些方法是虚拟的.因为它们是虚拟的,所以它们表现不佳.与虚拟方法相关的只是性能开销.这是一个问题.

版本控制更重要的一个问题.虚拟方法有两种思想流派.思想学院说,"一切都应该是虚拟的,因为有一天我可能想要覆盖它." 实用主义思想源于构建在现实世界中运行的真实应用程序,他说:"我们必须真正关注我们虚拟化的东西."

当我们在一个平台上制作虚拟东西时,我们会对未来的演变做出很多承诺.对于非虚方法,我们保证当您调用此方法时,将发生x和y.当我们在API中发布虚拟方法时,我们不仅承诺当您调用此方法时,x和y将会发生.我们还承诺,当你重写这个方法时,我们将按照这个特定的顺序对它们进行调用,并且状态将在这个和那个不变量中.

每当你在API中说虚拟时,你就是在创建一个回调钩子.作为操作系统或API框架设计师,您必须非常小心.您不希望用户在API中的任意点上覆盖和挂钩,因为您不一定能够做出这些承诺.人们可能无法完全理解他们在做虚拟事物时所做的承诺.

  • 好的面试问题,如果我在简历中看到同时包含Java和.Net的somone :) +1 (6认同)

Ell*_*iot 6

.Net 强制程序员定义哪些函数可以被覆盖,而 Java 函数在默认情况下可以被覆盖,除非使用 final 关键字。

如果您是开放/关闭原则的坚定拥护者,您可能倾向于支持 Java 方式。最好允许扩展类并覆盖方法,这样基本功能/代码就不会受到影响。出于这个原因,我支持/更喜欢 Java 方式。如果我换个角度看问题,我的看法可能正好相反。


Ger*_*ald 5

Java的方式更简单,默认情况下,C#的方式更精细,更安全,更高效.哪个更好的是在啤酒持有人的眼中.

  • 我认为恰恰相反.Java更复杂,因为它有隐藏的成本.虚拟方法在速度和设计成本方面都不是免费的. (5认同)
  • 那么你认为汇编语言是起诉最简单的语言吗? (2认同)

use*_*408 5

默认情况下虚拟比非虚拟好得多有两个主要原因。

  1. OOP有用性的主要原则是里氏替换原则多态性后期绑定。我一直使用策略模式,为此我希望我的方法是虚拟的。如果你是开放/封闭原则的粉丝,你应该更喜欢 Java 哲学。您应该能够在不更改源代码的情况下更改行为。您可以通过依赖注入和虚拟方法来做到这一点。
  2. 如果您调用非虚拟方法,那么您想从代码中知道您正在调用哪个类方法。.net 的缺陷是您无法从代码中得知这一点。
  3. 仅虚拟方法的另一个好处是测试代码要容易得多,因为您可以模拟您的(或第 3 方)类。在 Java 中使用 Mockito 进行测试非常简单。

例子

在 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# 设计者选择了一种不一致的混合方法。