Java 超类调用子类方法

3

我有以下这些类:

class A {
  public void f() { System.out.println("f() in A"); }
  public void g() { System.out.println("g() in A"); f(); }
}

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

为什么
B b = new B();
A a = b;
a.g();

打印输出这个

g() in A
f() in B

而不是

g() in A
f() in A

我有什么遗漏吗?


了解多态性和方法重写。 - Eran
5个回答

3
这是因为Java默认(并强制)在类的方法上使用动态分派,该特性确保调用方法时选择执行最专业化的版本。在您的情况下,由于B extends A,这意味着Bpublic void f()实现比A的更加专业化。因此,即使A a在静态上是A类型,在动态上也是B类型,因此该方法被选择执行。

2

是的,即使变量“a”是类型A,它所持有的对象引用是类型B,因此调用的是B中的f()。


1

实际上这不仅仅是多态性,它只是获得多态行为的一种方式,但有多种方式(即使在Java中)。 - Jack

0

现在你已经了解了多态和重写的概念。

由于你没有得到预期的输出,我建议通过方法“隐藏或遮蔽”来获得预期的输出。

如果你在派生类中重新定义基类的非静态和非私有方法,这被称为“重写”。

在这个例子中,A持有B的实例,因此从B而不是A调用了f()方法。

如果你在派生类中重新定义基类的静态方法/变量,这被称为“隐藏”或“遮蔽”。

在上面的例子中,只需为g()方法添加static修饰符,你就可以得到所需的输出。现在g()方法

class A {
  public static int i=10;
  public static void f() { 
    System.out.println("f() in A:i="+i); 
  }
  public void g() { System.out.println("g() in A"); f(); }
}

class B extends A {
  public static int i=20;
  public static void f() { 
      System.out.println("f() in B:i"+i); 
  }
}
public class Test2 {
    public static void main(String args[]){
        B b = new B();
        A a = b;
        a.g();
    }
}

输出:

g() in A
f() in A:i=10

0

对象的引用变量类型决定了可以访问哪些方法。

对象的类决定了哪些方法存在。这些存在但不可访问的方法可以通过强制转换来访问。

例如:((B) a).g(); 将允许您访问 B 版本的 G。这仅在 a 下面是 B 的情况下才有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接