18

可能重复:
java继承-请解释

我正在学习 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,将执行哪一个?

4

6 回答 6

24

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

假设 B 扩展 A,C 扩展 B。

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

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

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

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

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

例如,如果 A 和 B 都实现了方法 f(),并且方法调用的静态类型为 A,而涉及的动态类型为 C,则将调用 Bf():

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)和参数(无参数)的静态类型用于确定该特定调用的最佳匹配(最具体)方法签名,这是在编译时完成的。在这里,这显然是 Af()。

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

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

于 2012-10-25T22:01:05.687 回答
10

1.

A x = new A();

xA和 类型的实例化A

而在

A x = new B();

xB和 类型的实例化A


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

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

仍然会调用B's 方法。


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

(A)x.run_function();

相当于

(A)(x.run_function());
于 2012-10-25T20:52:54.813 回答
7

情况1:

当您在B中有一个不在A中的方法时,您会看到差异。

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

案例二:

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

A x = new B();

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

A x = new A();

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

于 2012-10-25T20:49:07.187 回答
4

此外:

A x = new B()

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

于 2012-10-25T20:54:46.457 回答
3
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类中的方法会在运行时基于动态绑定被调用。

于 2012-10-25T20:56:07.707 回答
1
  1. 没有真正的区别。实际上对于第二种情况,A 旧了 B 对象,但 B 是 A,所以没问题。在这种情况下,B 的行为类似于 A。

  2. 它将调用 B 的 run_function()

于 2012-10-25T20:51:10.423 回答