繁体   English   中英

继承和多态的怪异行为[Java]

[英]weird behavior of Inheritance and polymorphism [Java]

假设我有以下Java类:

class B {

  public void foo(B obj) {
      System.out.print("B1 ");
  }

  public void foo(C obj) {
      System.out.print("B2 ");
  }
}

public class C extends B {

  public void foo(B obj) {
      System.out.print("C1 ");
  }

  public void foo(C obj) {
      System.out.print("C2 ");
  }

  public static void main(String[] args) {
      B c = new C();
      B b = new B();

      b.foo(c); 
      c.foo(b); 
      c.foo(c); 

  }
}

为什么我得到以下结果:

B1

C1

C1

我不了解该零件到底发生了什么:

c.foo(b); //打印C1

c.foo(c); //打印C1

b和c变量都是TYPEB 。这是因为您将它们声明为:

**B** c = new C();
**B** b = new B();

当您通过c.foo(b)c.foo(c)因为它们都是B类类型,它们将打印“ C1”

您实际上可以通过运行代码来检查变量的类型:

 if (c instanceof B) {
        System.out.println("c is of type B"); //this will print
    }
    else {
        System.out.println("c is of type B");
    }


 if (b instanceof B) {
        System.out.println("b is of type B"); //this will print
    }
    else {
        System.out.println("b is of type B");
    }

Java虚拟机(JVM)为每个变量中引用的对象调用适当的方法。 它不会调用由变量类型定义的方法。 这是运行时多态。

B c = new C();  
c.foo(b); 
c.foo(c); 

在上述情况下,尽管变量类型是B,但是它所引用的对象是对象类型C。因此,将调用C类方法。

现在,为什么要打印出C1是因为Java Lang规范如下:

调用方法时(第15.12节),实际参数(和任何显式类型参数)的数量以及参数的编译时类型在编译时用于确定将被调用的方法的签名( §15.12.2)。 如果要调用的方法是实例方法,则将在运行时使用动态方法查找(第15.12.4节)确定要调用的实际方法。

这就是所谓的运行时多态。

当您进行超类引用并分配子类对象和调用方法时,它将调用以覆盖子类中的方法,而不是超类原始方法。

参考变量c在类型B中,这就是为什么它打印C1的原因

c.foo(c); //打印C1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM