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

时间:2009-06-10 00:58:44

标签: c# java oop

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

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

7 个答案:

答案 0 :(得分:40)

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

  

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

     

更重要的问题是版本控制。   有两种思想流派   虚拟方法。学院   思想说:“一切都应该如此   虚拟,因为我可能想要   有一天会超越它。“务实   思想学派,来自   构建运行的实际应用程序   现实世界说,“我们必须成为现实世界   真正小心我们的所作所为   虚拟“。

     

当我们制作虚拟的东西时   平台,我们做了很多   关于它如何演变的承诺   未来。对于非虚方法,我们   承诺,当你打电话给这个   方法,x和y会发生。什么时候我们   我们在API中发布虚拟方法   不仅在你打电话时承诺   这种方法,x和y会发生。我们   当你覆盖时也承诺   这个方法,我们将在此调用它   关于的特定顺序   这些其他的和国家将是   在这个和那个不变的。

     

每当你在API中说虚拟时,   你正在创建一个回拨钩子。如   OS或API框架设计器,   你必须要真正小心   那。您不希望用户覆盖   并在任何任意点挂钩   一个API,因为你不一定   做出这些承诺。人们可能会   不完全明白他们的承诺   正在制作什么东西   虚拟

答案 1 :(得分:5)

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

答案 2 :(得分:4)

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

如果您是Open/Close Principle的强烈支持者,您可能倾向于支持Java方式。最好允许扩展类并重写方法,以使基本功能/代码不受影响。出于这个原因,我支持/喜欢Java方式。如果我从不同的角度看问题,我的观点可能恰恰相反。

答案 3 :(得分:3)

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

答案 4 :(得分:2)

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

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

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

答案 5 :(得分:1)

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

Java遵循C ++并尝试充分利用其缺点。过度使用继承的危险尚未暴露,因此Java选择使用final关键字和virtual作为默认值。

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

答案 6 :(得分:1)

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