gpt4 book ai didi

java - 隐藏在 C# 和 Java 中的基方法

转载 作者:太空宇宙 更新时间:2023-11-03 18:28:39 25 4
gpt4 key购买 nike

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

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

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

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

然后运行以下命令:

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

我得到结果:

InheritanceTwo

如果我在 C# 中做完全相同的事情:

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

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

然后:

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

结果是

InheritanceOne

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

最佳答案

下面是一个稍微有趣一点的案例

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");
}
}

您看到的是 C# 和 Java 之间的一些差异,您可以让 C# 的行为像 Java 一样,正如方法 InheritanceB 将显示的那样。

默认情况下,C# 方法是 final方法,因此您需要采取积极措施,通过将方法标记为虚拟方法来重写该方法。因此,虚方法 InheratanceB 的行为将与您期望的方法一样,方法分派(dispatch)基于对象类型,而不是引用类型。例如

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

将同时生成 InheritanceB - Two,因为方法 InheritanceB 是虚拟的(能够被覆盖)和被覆盖(使用覆盖方法)。

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

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

将首先生成 InheritanceB - Two,然后生成 InheritanceB - One。这是因为(至少在简单的情况下)final 方法的调用是在编译时根据引用类型绑定(bind)的。这具有性能优势。虚拟方法的绑定(bind)需要不同于运行时,因为编译器可能不知道实例类。

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


更直接地回答您的问题

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

不,c# 知道构造类型(实例)和声明类型(引用)。即使实例隐藏了方法,它也会为覆盖的方法使用实例类型,为 final方法使用声明的类型。

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

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

关于java - 隐藏在 C# 和 Java 中的基方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27957424/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com