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

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

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

Anders Hejlsberg 🙁 C#首席架构师)

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

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

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

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

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

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

如果您是开放/关闭原则的坚定拥护者,您可能倾向于支持Java方式。 最好允许扩展类并重写方法,以使基本function/代码不受影响。 出于这个原因,我支持/喜欢Java方式。 如果我从不同的角度看问题,我的观点可能恰恰相反。

Anders Hejlsberg的回答: http : //www.artima.com/intv/nonvirtual.html

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

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

在Java中,如果将ClassB定义为

public class ClassB extends ClassA { @Override public void run() { } } 

和对象

 ClassA obj=new ClassB(); 

如果你调用obj.run(),你怎么知道该代码是否遵循多态打开/关闭原则的规则,或者它将编写与ClassA相关的方法? 在Java中,您将知道总是存在多态性。 制作模拟更容易,并且更容易扩展类并遵循Liskov替换原则。

另一方面,静态方法与类绑定,因此如果要调用与ClassA相关的方法,可以像这样定义该方法:

 public static run(ClassA obj) 

你可以用它来调用它

 ClassB obj=new ClassB(); ClassA.run(obj); 

从代码中你会知道你调用的方法是在ClassA中定义的,而不是在ClassB中定义的。 在这种情况下,您也不会有虚拟方法的开销。 (注意,在许多情况下,JIT也会减少虚拟方法的开销)。

对于C#,如果使方法非虚拟的原因是能够在子类中定义但不涉及多态,那么您可能没有真正的原因进行子类化。

如果是设计,我建议密封(最终用java),而不是单独的方法,如果可能的话。

Jon Skeet说,在C#中,默认情况下应该密封类,因为默认情况下方法也是非虚拟的。 约书亚布洛赫说你应该设计inheritance或禁止它(使课程最终)。 C#设计师选择了一种不一致的混合方法。

这是时间的扰动。 C ++使用virtual关键字和final作为默认值。

Java遵循C ++并试图充分发挥其优缺点并改进其缺点。 过度使用inheritance的危险还没有发现,因此Java选择使用final关键字和virtual作为默认值。

C#遵循Java并具有后见之明的好处。 在观察Java的经验之后,Anders选择回到C ++约定。

一如既往,有利有弊。 C#使AOP更难实现,但后见之明可能是其他人提到的20/20。 这一切都归结为您是否认为必须为扩展设计课程,或者只是为了不可预见的行为修改而保持开放。 在设计语言时,这是一个难以回答的问题。 我认为行业经验倾向于采用C#采取的更保守的方法。