【问题标题】:Java: difference between A x = new A() and A x = new B() when B extends A [duplicate]Java:当B扩展A时,A x = new A()和AN x = new B()之间的区别[重复]
【发布时间】:2012-10-25 20:48:14
【问题描述】:

可能重复:
java inheritance - please explain

我正在学习 Java,我有两个问题:

  1. 有什么区别:

    A x = new A();
    

    A x = new B();
    

    考虑到:

    class A
    class B extends A
    
  2. 两者有什么区别:

    A x = new B();
    (A)x.run_function();
    

    假设A和B都有函数run_function,会执行哪一个?

【问题讨论】:

    标签: java inheritance


    【解决方案1】:

    最重要的区别在于对象的静态和动态类型以及对对象的引用。

    说 B 扩展 A,C 扩展 B。

    对象的动态类型(new 中使用的类型)是它的实际运行时类型:它定义了对象的实际方法。

    对象引用(变量)的静态类型是编译时类型:它定义,或者更确切地说,声明可以在变量引用的对象上调用哪些方法。

    变量的静态类型应该始终是它所引用对象的动态类型的相同类型或超类型。

    所以在我们的示例中,具有静态类型 A 的变量可以引用具有动态类型 A、B 和 C 的对象。 静态类型 B 的变量可以引用动态类型 B 和 C 的对象。 静态类型 C 的变量只能引用动态类型 C 的对象。

    最后,在对象引用上调用方法是静态和动态类型之间微妙而复杂的交互。 (如果您不相信我,请阅读有关方法调用的 Java 语言规范。)

    例如,如果A和B都实现了一个方法f(),并且方法调用的静态类型是A,而涉及的动态类型是C,那么会调用B.f():

    B extends A, C extends B
    public A.f() {}
    public B.f() {}
    A x = new C(); // static type A, dynamic type C
    x.f(); // B.f() invoked
    

    大大简化:首先使用接收者(类型 A)和参数(无参数)的静态类型来确定该特定调用的最佳匹配(最具体)方法签名,这是在编译时完成的.这里,这显然是 A.f()。

    然后,在运行时的第二步中,动态类型用于定位我们方法签名的实际实现。我们从类型 C 开始,但是我们没有找到 f() 的实现,所以我们向上移动到 B,并且我们有一个与 A.f() 的签名匹配的方法 B.f()。所以 B.f() 被调用。

    在我们的示例中,我们说方法 B.f() 覆盖了方法 A.f()。在类型层次结构中覆盖方法的机制称为子类型多态性。

    【讨论】:

    • 解释得很好!!
    • 官方文档中是否有任何地方记录了这一点。我发现这个解释有点难以理解,可以参考一些文档。谢谢!
    【解决方案2】:

    1.

    A x = new A();
    

    xAA 类型的实例化。

    而在

    A x = new B();
    

    xBA 类型的实例化。


    2.这里需要注意的是(第二种情况)如果你调用x.someMethod()B的方法 将被调用,而不是A 的方法(这称为动态绑定,与静态绑定相对)。此外,强制转换只会改变 type,所以

    A x = new B();
    ((A)x).run_function();  // Need extra parenthesis!
    

    仍会调用B的方法。


    正如我上面所说,你需要包括那些额外的括号,因为

    (A)x.run_function();
    

    等价于

    (A)(x.run_function());
    

    【讨论】:

      【解决方案3】:

      案例 1:

      当您在 B 中有一个不在 A 中的方法时,您会看到不同之处。

      当您尝试使用引用“x”调用该方法时,它将不可见。

      案例 2:

      由于多态性,所有方法调用都将基于对象类型而不是引用类型(静态方法除外)

      A x = new B();
      

      在这种情况下,Brun_function 将被执行。

      A x = new A();
      

      在这种情况下,Arun_function 将被执行。

      【讨论】:

        【解决方案4】:

        还有:

        A x = new B()
        

        您将无法执行在B 中定义和在A 中未定义的方法。但是如前所述,由于 Java 中的多态性,如果您执行任何方法并且 B' 已覆盖这些方法,那么它将使用 B 的实现。

        【讨论】:

          【解决方案5】:
          1.What is the difference between: A x = new A();and A x = new B();
          

          不同之处在于,在第一种情况下,您正在实例化一个类型为 A 的类。因此,您将只能调用在 A 中定义的方法。在第二种情况下,如果 A 和 B 中都存在相同名称的方法,则 B 实现将在运行时被调用。

          但是,在第二种情况下,使用反射,也可以调用在 B 类而不是 A 类中定义的方法。

          A x = new B(); (A)x.run_function();假设A和B都有 函数run_function,会执行哪一个?

          记住 - 覆盖是在运行时决定的,而重载是在编译时决定的。

          所以B类中的方法会在运行时基于动态绑定被调用。

          【讨论】:

          • 覆盖不是在运行时决定的。它基于子类化、方法签名和可见性,所有这些都是静态概念。所以编译器知道覆盖和覆盖的方法。
          • 在运行时确定要调用的重写方法。
          • 不,动态绑定发生在运行时。
          • @SteveKuo,rationalSpring:那是另一种说法。
          • @eljenso - 你暗示要调用哪个重写方法的决定是在编译时决定的。这是不正确的。它是在运行时决定的。
          【解决方案6】:
          1. 没有真正的区别。实际上对于第二种情况,A 旧了 B 对象,但 B 是 A,所以没问题。在这种情况下,B 的行为类似于 A。

          2. 会调用B的run_function()

          【讨论】:

            猜你喜欢
            • 2014-12-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-12-18
            • 2017-04-26
            • 1970-01-01
            • 1970-01-01
            • 2019-07-16
            相关资源
            最近更新 更多