15

假设 Java 有这些分层类:

class A 
{
}
class B extends A
{
    public void m()
    {
        System.out.println("B\n");
    }
}
class C extends B
{
    public void m()
    {
        System.out.println("C\n");
    }
}
class D extends C
{
    public static void main(String[] args)
    {
        A a = new D();
        // a.m(); // doesn't work
        B b = new D();
        b.m();
        C c = new D();
        c.m();
        D d = new D();
        d.m();
    }
}

这是 C# 中相同代码的(盲目)重复:

using System;
class A 
{   
}
class B : A
{
    public void M()
    {
        Console.WriteLine("B");
    }
}
class C : B
{
    public void M() // I need to use public new void M() to avoid the warning
    {
        Console.WriteLine("C");
    }
}
class D : C
{
    public static void Main(String[] args)
    {
        A a = new D();
        // a.M(); // doesn't work       
        B b = new D();
        b.M();
        C c = new D();
        c.M();
        D d = new D();
        d.M();
    }
}

当我执行 Java 代码时,我得到了C-C-C而 C# 返回B-C-C.

对我来说,C# 的结果更有意义,因为引用 B 调用了它自己的方法。

  • Java 设计者决定打印C-C-C而不是打印的逻辑是B-C-C什么?我的意思是,为什么引用 B 使用 C 中的覆盖方法?这种方法有什么好处?
  • 如何B-C-C像 C# 一样更改 Java 代码以打印出来?我的意思是,我怎样才能教 java 调用它使用的确切引用的方法?
  • 如何更改 C# 代码以打印出来C-C-C?我的意思是,我怎样才能教 C# 调用覆盖方法?
4

4 回答 4

13

它用于虚函数定义:

虚函数或虚方法是一种函数或方法,其行为可以在继承类中被具有相同签名的函数覆盖。这个概念是面向对象编程 (OOP) 的多态部分的一个非常重要的部分。

在 C# 中,您应该将该方法声明为 virtual 以便被覆盖,如 MSDN 中所示:

由于该M方法不是虚拟的,因此b.M()即使b变量实际上是一个D实例,它也会执行。

在 Java 中,默认情况下,每个非静态方法都是虚拟的,因此当您覆盖一个方法(即使没有@Override注释)时,其行为b.M()将是d.M()继承该c.M()方法行为的行为。

如何像 C# 一样更改 Java 代码以打印 BCC?我的意思是,我怎样才能教 java 调用它使用的确切引用的方法?

你根本无法在 Java 中做到这一点。类中的M方法C会覆盖中的M方法B。添加final修饰符B#M只会使那个C或其他B孩子无法覆盖该M()方法。

如何更改 C# 代码以打印出 CCC?我的意思是,我怎样才能教 C# 调用覆盖方法?

M将类中的方法更改为并在B类中virtual覆盖它C

class B : A
{
    public virtual void M()
    {
        Console.WriteLine("B");
    }
}
class C : B
{
    public override void M() // I need to use public new void M() to avoid the warning
    {
        Console.WriteLine("C");
    }
}
于 2012-11-10T15:03:05.033 回答
8
  1. 在java中,所有方法默认都是虚拟的。派生类中的方法会覆盖基类中的方法。在 C# 中它们不是。

  2. 好像你不能这样做。但是您可以通过将其声明为 来防止派生类覆盖此方法final

  3. virtual在基类中用关键字声明此方法,override在派生中用关键字声明。

于 2012-11-10T14:59:30.407 回答
1

Java 设计者决定打印 CCC 而不是 BCC 背后的逻辑是什么?

默认情况下,Java 使方法成为虚拟方法。过去有一种理解认为这是一种很好的做法,而在 Java 诞生的时候,可能正处于这种理解的顶峰。

如今——尽管许多人确实坚持它——也有更多的阻力(特别是当虚拟方法向类开放了意想不到的子类实现选择时)。

(注意,这里没有对错之分,每种方法都有其优点和缺点。)

如何像 C# 一样更改 Java 代码以打印 BCC?

宣布他们final

如何更改 C# 代码以打印出 CCC?

在定义它们的类(在问题中)和子类中virtual声明它们。abstractBoverride

于 2012-11-10T15:00:42.833 回答
0

Java 设计者决定打印 CCC 而不是 BCC 背后的逻辑是什么?我的意思是,为什么引用 B 使用 C 中的覆盖方法?这种方法有什么好处?

看你从 D 类对象调用方法,它继承了 C 类的 M 方法。引用类型在 Java 中并不重要——重要的是哪个类引用了对象。

于 2012-11-10T14:59:42.777 回答