【发布时间】:2012-10-25 20:48:14
【问题描述】:
我正在学习 Java,我有两个问题:
-
有什么区别:
A x = new A();和
A x = new B();考虑到:
class A class B extends A -
两者有什么区别:
A x = new B(); (A)x.run_function();假设A和B都有函数
run_function,会执行哪一个?
【问题讨论】:
标签: java inheritance
我正在学习 Java,我有两个问题:
有什么区别:
A x = new A();
和
A x = new B();
考虑到:
class A
class B extends A
两者有什么区别:
A x = new B();
(A)x.run_function();
假设A和B都有函数run_function,会执行哪一个?
【问题讨论】:
标签: java inheritance
最重要的区别在于对象的静态和动态类型以及对对象的引用。
说 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()。在类型层次结构中覆盖方法的机制称为子类型多态性。
【讨论】:
1.在
A x = new A();
x 是A 和A 类型的实例化。
而在
A x = new B();
x 是 B 和 A 类型的实例化。
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());
【讨论】:
案例 1:
当您在 B 中有一个不在 A 中的方法时,您会看到不同之处。
当您尝试使用引用“x”调用该方法时,它将不可见。
案例 2:
由于多态性,所有方法调用都将基于对象类型而不是引用类型(静态方法除外)
A x = new B();
在这种情况下,B 类 run_function 将被执行。
A x = new A();
在这种情况下,A 类 run_function 将被执行。
【讨论】:
还有:
A x = new B()
您将无法执行在B 中定义和在A 中未定义的方法。但是如前所述,由于 Java 中的多态性,如果您执行任何方法并且 B' 已覆盖这些方法,那么它将使用 B 的实现。
【讨论】:
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类中的方法会在运行时基于动态绑定被调用。
【讨论】:
没有真正的区别。实际上对于第二种情况,A 旧了 B 对象,但 B 是 A,所以没问题。在这种情况下,B 的行为类似于 A。
会调用B的run_function()
【讨论】: