Java Vs C#:带有方法覆盖的Java和C#子类在同一场景中输出不同的结果

Fai*_*her 11 c# java oop inheritance overriding

好!我有相同的代码用JavaC#编写,但输出不同!

class A
{
    public void print() 
    {
        Console.WriteLine("Class A");
    }
}

class B : A 
{
    public void print()
    {
        Console.WriteLine("Class B");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new B();
        a.print();
        Console.Read();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:A类.它在C#中.

但是当在Java中运行相同的代码时,输出是B类.这是Java代码:

class A
{
    public void print() 
    {
        System.out.println("Class A");
    }
}

class B extends A 
{
    public void print()
    {
        System.out.println("Class B");
    }
}


public class Program{

 public static void main(String []args){
    A a = new B();
    a.print();
 }
}
Run Code Online (Sandbox Code Playgroud)

那么,为什么会出现不同的结果呢?我知道,在Java中,默认情况下所有方法都是虚拟的,这就是Java输出B类的原因.

另一件事是,两种语言都声称它们是由C++出现或启发的,然后为什么它们显示不同的结果,而两者都有相同的基本语言(Say).

这条线A a = new B();实际上做了什么?不是B持有对象吗?如果是这样,那么为什么C#显示A类而Java显示B类呢?

注意在采访中询问了上述相同代码的问题.我回答了输出类B(关于Java),但他说A类将是正确的输出.

谢谢!

das*_*ght 5

这是因为在 C# 中,派生类的方法隐藏而不是重写其基类的方法。您想要重写的方法需要在基类中使用关键字显式标记,并在派生类中virtual使用关键字显式标记。override

相比之下,在 Java 中,默认情况下所有方法都是虚拟的:只需指定相同的签名就足以进行覆盖。

以下是如何使 C# 程序与 Java 程序等效:

class A
{
    public virtual void print() // Add "virtual"
    {
        Console.WriteLine("Class A");
    }
}

class B : A 
{
    public override void print()// Add "override"
    {
        Console.WriteLine("Class B");
    }
}
Run Code Online (Sandbox Code Playgroud)

之后A a = new B(),变量a持有 的对象B,但输出是“Class A”!它不应该调用类的方法吗B

当您隐藏某个方法而不是重写它时,派生类会保留两种方法 - 基类中的方法和派生类中的方法。外部调用者仍然可以访问这两种方法。他们可以通过使用适当的静态类型的对象来决定调用这两个方法中的哪一个。这是一个例子:

    B b = new B();
    b.print();      // Prints "Class B"
    ((A)b).print(); // Prints "Class A"
Run Code Online (Sandbox Code Playgroud)

ideone 上的演示。

当您使用virtual/时override,您只能从外部访问一种方法 - 即派生类中的方法。基类中的方法可以被派生类的方法访问,但不能被派生类的外部用户访问。


Stu*_*tLC 4

在 Java 中,非静态方法是 virtual,而在 C# 中则不是。您需要在 print 方法中使用virtualoverride关键字才能在 C# 中获得相同的行为。

C# 中的多态行为:

class A
{
    public virtual void print() 
    {
        Console.WriteLine("Class A");
    }
}

class B : A 
{
    public override void print()
    {
        Console.WriteLine("Class B");
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑

回到原来的 C# 代码,B.print当您在子类及其超类中使用相同的方法签名时,您将收到编译时警告,即:

“print”需要关键字“new”,因为它隐藏了方法“MyNamespace.A.print()”

这很好地表明该方法不会被多态/虚拟地调用。为了避免警告(并保留原来的 C# 行为),您需要在 B 中添加new

    public new void print()
Run Code Online (Sandbox Code Playgroud)