Java:当A扩展A 时,A x = new A()和A x = new B()之间的差异
可能重复:
javainheritance – 请解释
我正在学习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
函数,哪一个会被执行?
最重要的区别在于静态和动态类型的对象以及对象的引用。
说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 Af() {} public Bf() {} A x = new C(); // static type A, dynamic type C xf(); // Bf() invoked
大大简化:首先使用接收器(类型A)和参数(无参数)的静态类型来确定特定调用的最佳匹配(最具体)方法签名,这在编译时完成。 在这里,这显然是Af()。
然后,在运行时的第二步中,动态类型用于定位方法签名的实际实现。 我们从类型C开始,但是我们没有找到f()的实现,所以我们向上移动到B,并且我们有一个方法Bf()匹配Af()的签名。 所以调用了Bf()。
在我们的例子中,我们说方法Bf()重写方法Af()。 在类型层次结构中重写方法的机制称为子类型多态。
1.在
A x = new A();
x
是A
和A
类型的实例。
而在…
A x = new B();
x
是B
和A
类型的实例。
2.这里需要注意的重要事项是(在第二种情况下)如果调用x.someMethod()
,将调用B
的方法,而不是A
的方法(这称为动态绑定 ,而不是静态绑定) )。 此外,铸造仅改变类型 ,因此
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();
在这种情况下,将执行类run_function
。
1.What is the difference between: A x = new A();and A x = new B();
不同之处在于,在第一种情况下,您要实例化一个类型为A的类。因此,您只能调用A中定义的方法。在第二种情况下,如果A和B中都存在相同的名称方法,则B实现将在运行时调用。
但是,在第二种情况下,使用reflection,也可以调用在B类中定义而不在A类中定义的方法。
A x = new B(); (A)x.run_function();
假设A和B都有run_function函数,哪一个会被执行?
记住 – 在运行时决定覆盖,而在编译时决定重载。
因此,将在运行时基于动态绑定调用类B中的方法。
-
没有真正的区别。 实际上对于第二种情况A olds是B对象,但B是A,所以这没问题。 在这种情况下B表现得像A.
-
它将调用B的run_function()
此外还有:
A x = new B()
您将无法执行B
中定义的方法以及未在A
定义A
。 但是如前所述,由于Java中的多态性,如果你执行任何方法并且B'
已经覆盖了这些方法,那么它将使用B
的实现。