我正在学习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
函数,哪一个会被执行?
答案 0 :(得分:16)
最重要的区别在于静态和动态类型的对象和对象的引用。
说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,并且我们有一个方法B.f()匹配A.f()的签名。所以调用B.f()。
在我们的例子中,我们说方法B.f()会覆盖方法A.f()。在类型层次结构中重写方法的机制称为子类型多态。
答案 1 :(得分:7)
1。在
A x = new A();
x
是A
和A
类型的实例化。
而在
A x = new B();
x
是 B
和A
类型的实例。
2。这里需要注意的重要一点是(在第二种情况下),如果您拨打x.someMethod()
, B
<的方法将调用/ em> ,而不是A
的方法(这称为动态绑定,而不是静态绑定)。此外,强制转换仅更改类型,因此
A x = new B();
((A)x).run_function(); // Need extra parenthesis!
仍然会调用B
的方法。
正如我上面所说,你需要包括那些额外的括号,因为
(A)x.run_function();
相当于
(A)(x.run_function());
答案 2 :(得分:5)
案例1:
如果 B 中的方法不在 A 中,您会发现不同。
当您尝试使用引用'x'调用该方法时,它将不可见。
案例2:
由于多态性(静态方法除外),所有方法调用都将基于对象类型而非引用类型
A x = new B();
在这种情况下,B
类run_function
将被执行。
A x = new A();
在这种情况下,A
类run_function
将被执行。
答案 3 :(得分:3)
1.What is the difference between: A x = new A();and A x = new B();
不同之处在于,在第一种情况下,您将实例化一个类型为A的类。因此,如果A和B中同一名称方法同时存在,则只能调用A中定义的方法。在第二种情况下,然后将在运行时调用B实现。
但是,在第二种情况下,使用反射,也可以调用在B类中定义而不在A类中定义的方法。
A x = new B(); (A)x.run_function();
让我们说A和B都有 函数run_function,将执行哪一个?
记住 - 在运行时决定覆盖,而在编译时决定重载。
因此,将在运行时基于动态绑定调用类B中的方法。
答案 4 :(得分:1)
没有真正的区别。实际上对于第二种情况A olds是B对象,但B是A,所以没问题。在这种情况下,B的行为类似于A.
它将调用B的run_function()
答案 5 :(得分:1)
此外还有:
A x = new B()
您将无法执行B
中定义且未在A
中定义的方法。但是如前所述,由于Java中的多态性,如果您执行任何方法并且B'
已覆盖这些方法,那么它将使用B
的实现。