Java继承方法的调用规则、可见性及静态/动态类型作用问询
Java继承与多态问题解析
先看示例代码:
public class Test { public static void main(String[] args) { A a = new A(3); A b = new B(1, 4); b.methodOne(6); // <----- 此处,我认为会使用"b.m"和"b.increase" } } public class A { private int m; private int n; public A(int n) { m = n; } public void methodOne(int i) { m -= i; increase(i); } public void increase(int i) { m += 2 * i; } public void visibilityTest() { n++; // <----- 我认为调用b.visibilityTest()是可行的 // 因为它遵循A类的可见性规则 } } public class B extends A { private int m; public B(int m, int n) { super(n); this.m = m + 1; } public void increase(int i) { m += i; } }
如注释所述,假设执行b.methodOne(6)时,尽管methodOne继承自父类A,但会使用对象b的m属性与B类的increase方法(而非父类A的super.m)。针对这个场景,解答以下问题:
问题1:上述观点是否正确?继承方法通常会使用子类的方法与属性吗?
你的观点不完全正确,得分两部分看:
- 关于
increase方法:这部分是对的。Java的方法调用是动态绑定,只要子类重写了父类的方法,执行时会调用对象实际类型(也就是B类)的重写方法,所以methodOne里调用的increase(i)确实会执行B类的版本。 - 关于
m属性:这部分错了。Java的属性没有多态性,是静态绑定的。methodOne是A类的方法,里面直接写的m会指向A类自己的私有m,和B类里的m是两个完全独立的变量,彼此互不干扰。所以执行m -= i时,修改的是A类的m,不是B类的。
简单总结:继承的方法里,调用的方法会优先用子类重写的版本,但直接访问的属性是当前方法所在类的属性,不会自动用子类的同名属性。
问题2:在语句A b = new B(1,4)中,静态类型与动态类型分别起到什么作用?
- 静态类型(A):属于编译期类型,编译器会根据这个类型检查你能调用哪些方法/属性。比如你不能通过
b直接调用B类独有的方法,编译器会报错,因为它只认A类型有的成员。 - 动态类型(B):是运行期的实际对象类型,决定了执行方法时到底调用哪个版本(比如重写的
increase方法,就由动态类型B决定)。
一句话概括:编译阶段看静态类型做语法校验,运行阶段看动态类型执行实际逻辑。
问题3:继承方法是否遵循父类的可见性规则?例如,调用b.visibilityTest()时,能否访问父类A的私有属性n?
能正常访问,因为visibilityTest是A类定义的方法,方法的可见性权限是看方法所在的类,而不是调用该方法的对象类型。A类的方法可以访问自己的私有成员n,不管这个方法是被A类对象还是子类B的对象调用,执行时都能正常访问A类的n。
内容的提问来源于stack exchange,提问作者grecode97
相关产品推荐
相关产品推荐

