可能重复:
java继承 - 请解释
我正在学习Java,我有两个问题:
有什么区别:
A x = new A();
Run Code Online (Sandbox Code Playgroud)
和
A x = new B();
Run Code Online (Sandbox Code Playgroud)
考虑到:
class A
class B extends A
Run Code Online (Sandbox Code Playgroud)有什么区别:
A x = new B();
(A)x.run_function();
Run Code Online (Sandbox Code Playgroud)
假设A和B都有这个功能run_function,哪一个会被执行?
elj*_*nso 17
最重要的区别在于静态和动态类型的对象以及对象的引用.
说B扩展A和C扩展B.
对象的动态类型(新的类型)是它的实际运行时类型:它定义了对象的实际方法.
对象引用(变量)的静态类型是编译时类型:它定义或更确切地声明可以在变量引用的对象上调用哪些方法.
变量的静态类型应始终与它引用的对象的动态类型的类型或超类型相同.
因此在我们的示例中,具有静态类型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
Run Code Online (Sandbox Code Playgroud)
大大简化:首先使用接收器(类型A)和参数(无参数)的静态类型来确定特定调用的最佳匹配(最具体)方法签名,这是在编译时完成的.在这里,这显然是Af().
然后,在运行时的第二步中,动态类型用于定位方法签名的实际实现.我们从类型C开始,但是我们没有找到f()的实现,所以我们向上移动到B,并且我们有一个方法Bf()匹配Af()的签名.所以调用了Bf().
在我们的例子中,我们说方法Bf()会覆盖方法Af().在类型层次结构中重写方法的机制称为子类型多态.
1.在
A x = new A();
Run Code Online (Sandbox Code Playgroud)
x是A类型的实例化A.
而在...
A x = new B();
Run Code Online (Sandbox Code Playgroud)
x是B类型的实例化A.
2.这里需要注意的重要事项是(在第二种情况下)如果调用x.someMethod(),将调用方法B,而不是方法A(这称为动态绑定,而不是静态绑定).此外,铸造只改变了类型,所以
A x = new B();
((A)x).run_function(); // Need extra parenthesis!
Run Code Online (Sandbox Code Playgroud)
仍会打电话给B我的方法.
正如我上面所说,你需要包括那些额外的括号
(A)x.run_function();
Run Code Online (Sandbox Code Playgroud)
相当于
(A)(x.run_function());
Run Code Online (Sandbox Code Playgroud)
情况1:
当您在B中有一个方法而不是A中的方法时,将会看到差异。
当您尝试使用引用“ x”调用该方法时,该方法将不可见。
情况2:
由于多态性,所有方法调用将基于对象类型而不是引用类型(静态方法除外)
A x = new B();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,将执行B类run_function。
A x = new A();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,将执行A类run_function。