隐藏在 C# 和 Java 中的基本方法 [英] Base method hiding in C# and Java

查看:51
本文介绍了隐藏在 C# 和 Java 中的基本方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我来自 Java 背景,目前正在学习 C#.我只是对(我认为的)对象从基类/派生类访问方法的方式有所不同感到非常惊讶.这是我的意思:

在 Java 中,如果我做这样的事情

<块引用>

class InheritanceTesting{public void InheritanceOne(){System.out.println("InheritanceOne");}}类 NewInherit 扩展了 InheritanceTesting{public void InheritanceOne(){System.out.println("继承二");}}

然后运行以下命令:

<块引用>

 public static void main(String[] args) {InheritanceTesting inh = new NewInherit();inh.InheritanceOne();}

我得到了结果:

<块引用>

继承二

如果我在 C# 中完全一样:

<块引用>

class InheritanceTesting{public void InheritanceOne(){Console.WriteLine("InheritanceOne");}}类 NewInherit : InheritanceTesting{public new void InheritanceOne(){Console.WriteLine("InheritanceTwo");}}

那么:

<块引用>

InheritanceTesting inh = new NewInherit();inh.InheritanceOne();

结果是

<块引用>

InheritanceOne

我记得在 Java 中被教导对象知道它被实例化为什么类型",因此,当我调用被覆盖的方法时并不奇怪.这是否意味着在 C# 中情况正好相反?对象只知道"其声明的类型?如果是这样,其中的逻辑/优势是什么?在我看来,Java 将基类视为接口 - 这是您的类型,这是您的实际实现.我是 C# 新手,也许我在这里遗漏了一些明显的东西?

解决方案

一个稍微有趣的案例如下

class InheritanceTesting{public void InheritanceOne()//Java 等价物是//public final void InheritanceA(){Console.WriteLine("InheritanceA - 一");}public virtual void InheritanceB()//Java 等价物是//public void InheritanceB()//注意 final 的删除{Console.WriteLine("继承B - 一");}}类 NewInherit : InheritanceTesting{public new void InheritanceOne()//没有与此语句等效的 Java{Console.WriteLine("继承A - 两个");}公共覆盖 void InheritanceB()//Java 等价物是//public void InheritanceB(){Console.WriteLine("继承B - 两个");}}

您所看到的是 C# 和 Java 之间的一些差异,您可以让 C# 表现得像 Java 一样,如方法 InheritanceB 将显示的那样.

默认情况下,C# 方法是最终的,因此您需要采取积极措施,通过将方法标记为虚拟方法来覆盖方法.因此,虚拟方法 InheratanceB 的行为将与您期望的方法行为相同,方法分派基于对象类型,而不是引用类型.例如

 NewInherit 示例 = new NewInherit();继承测试 secondReference = 示例;示例.继承B();secondreference.InheritanceB();

都将产生 InheritanceB - Two 作为方法 InheritanceB 是虚拟的(能够被覆盖)和被覆盖(使用覆盖方法).

您所看到的称为方法隐藏,其中方法不能被覆盖(非虚拟)但可以隐藏,隐藏方法仅在引用(而不是对象)是派生类型时隐藏,所以

 NewInherit 示例 = new NewInherit();继承测试 secondReference = 示例;示例.继承A();secondreference.InheritanceA();

将首先产生 InheritanceB - TwoInheritanceB - One 第二次.这是因为(至少在简单的情况下)最终方法的调用是在编译时根据引用类型绑定的.这具有性能优势.虚拟方法的绑定需要与运行时不同,因为编译器可能不知道实例类.

在实践中方法隐藏并没有被广泛使用,并且一些组织有禁止它的编码标准.通常的做法是将您期望子类能够覆盖的方法标记为 virtual,并在子类中使用关键字 override.

<小时>

更直接地回答您的问题

<块引用>

这是否意味着在 C# 中情况正好相反?仅对象知道"其声明的类型?

不,c# 知道构造类型(实例)和声明类型(引用).即使实例隐藏了方法,它也将实例类型用于重写的方法和声明的类型用于最终方法.

<块引用>

如果是这样,其中的逻辑/优势是什么?

不是这样,我相信在可能的情况下在编译时绑定会带来性能优势,例如允许内联方法.同样正如所解释的那样,不会失去灵活性,因为您可以通过使用 virtualoverride 关键字获得与 Java 相同的行为.

I am coming from Java background and currently learning C#. I just had a big surprise regarding (what I perceive as ) a difference in a way that an object accesses methods from base/derived class. Here is what I mean:

In Java if I do something like this

class InheritanceTesting
{
    public void InheritanceOne()
    {
        System.out.println("InheritanceOne");
    }
}

class NewInherit extends InheritanceTesting 
{
    public void InheritanceOne()
    {
        System.out.println("InheritanceTwo");
    } 
 }

then run the following:

 public static void main(String[] args)    {
    InheritanceTesting inh = new NewInherit();
        inh.InheritanceOne();    
 }

I get the result:

InheritanceTwo

If I do exactly the same in C#:

class InheritanceTesting
{
    public void InheritanceOne()
    {
        Console.WriteLine("InheritanceOne");
    }
}

class NewInherit : InheritanceTesting
{
    public new void InheritanceOne()
    {
        Console.WriteLine("InheritanceTwo");
    }
}

Then:

InheritanceTesting inh = new NewInherit();
        inh.InheritanceOne();

result is

InheritanceOne

I remember being taught in Java that "object knows what type it is instantiated to", therefore, no surprises when I call the overridden method. Does this mean that the situation is the opposite in C#? Object only "knows" its declared type? If so, what is the logic/advantage in that? It seems to me that Java treats base classes like interfaces - here is your type and here is your actual implementation. I am new to C# and maybe I am missing something obvious here?

解决方案

A slightly more interesting case is the following

class InheritanceTesting
{
    public void InheritanceOne() 
    // Java equivalent would be
    // public final void InheritanceA()
    {
        Console.WriteLine("InheritanceA - One");
    }


    public virtual void InheritanceB()
    // Java equivalent would be
    // public void InheritanceB() // note the removing of final
    {
        Console.WriteLine("InheritanceB - One");
    }
}

class NewInherit : InheritanceTesting
{
    public new void InheritanceOne() 
    // There is no Java equivalent to this statement
    {
        Console.WriteLine("InheritanceA - Two");
    }


    public override void InheritanceB()
    // Java equivalent would be
    // public void InheritanceB()
    {
        Console.WriteLine("InheritanceB - Two");
    }
}

What you are seeing are some of the difference between C# and Java, you can get C# to behave like Java as the method InheritanceB will show.

C# methods are final by default, so you need to take a positive action to make it possible to override a method by marking it as virtual. So the virtual method InheratanceB will behave like you expect methods to behave, with method dispatch based on the object type, not the reference type. e.g.

 NewInherit example = new NewInherit();
 InheritanceTesting secondReference = example;
 example.InheritanceB();
 secondreference.InheritanceB();

Will both produce InheritanceB - Two as the method InheritanceB was virtual (able to be overriden) and overridden (with the override method).

What you where seeing is called method hiding, where the method can not be overriden (non-virtual) but can be hidden, hidden methods are only hidden when the reference (not the object) is of the derived type so

 NewInherit example = new NewInherit();
 InheritanceTesting secondReference = example;
 example.InheritanceA();
 secondreference.InheritanceA();

Will produce InheritanceB - Two first and InheritanceB - One second. this is because (at least in the simple cases) invocation of final methods is bound at compile time based on the reference type. This has a performance benifit. Binding of virtual methods needs to be differed to runtime as the compiler may not be aware of the instances class.

In practice method hiding is not widely used, and some organisation have coding standards forbidding it. the normal practice is to mark the methods you expect a sub-class to be able to override as virtual and in the sub-class use the keyword override.


More directly answering your questions

Does this mean that the situation is the opposite in C#? Object only "knows" its declared type?

No, c# knows both the constructed type (instance) and the declared type (reference). It uses the instance type for overridden methods and the declared type for final methods even if the instance has hidden the method.

If so, what is the logic/advantage in that?

No the case, I believe there are performance benefits in binding at compile time where possible, e.g. allow in-lining of methods. Also as explained there is not a loss of flexibility as you can have the same behaviour as Java by using the virtual and override keywords.

这篇关于隐藏在 C# 和 Java 中的基本方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆