子类继承父类方法的问题

class Sup {
    int a = 9;
    public void printA(){
        System.out.println(a);
    }
}

class Sub extends Sup{
    int a = 90;
    public static void main(String[] args){
        Sub s = new Sub();
        s.printA(); // 9
    }
}

我一开始的理解是这样的,当对象调用非静态方法的时候会隐式传递一个 this, 所以 s.printA() 就传递了一个 this, printA 方法相当于

public void printA(){
    System.out.println(this.a);
}

这了this引用的对象应该是 s ,也就是子类对象,输出应该是 90。 为何会是 9呢?

阅读 5.2k
6 个回答

上几张图

clipboard.png
这个是Sub子类的class文件,根据字节码显示(注意看我圈圈的部分),这里调用的是父类的printA方法(Sup.printA)。这个很好理解,因为Sub类作为子类继承了父类Sup,自然会拥有父类的public的方法。

clipboard.png

Sub类的main方法中调用的是父类的printA方法

clipboard.png
这个是父类的class文件,同样请注意圈圈的部分,printA调用的a变量是父类的变量(Sup.a),所以说打印的是9

this 是子类的,但是父类的 a 变量还是存在的,只是被隐藏了而已,这种查找应该是就近原则吧,你调用父类方法,如果父类中有这变量,肯定是用父类的,我是这样理解的。

新手上路,请多包涵

因为printA是在Sup中定义的,而Sup中定义的变量a的值,所以Sup会直接使用自己class中的a来进行编译。
至于为什么不是90,是因为你没有在子类Sub中Override掉printA方法,所以printA方法仍然是父类实现的,父类是看不到子类中定义的元素的。
在JVM中,父类会为自己在堆区开辟一个内存,子类也会开辟一个内存,所以在内存中会有两个a,一个是父类内存区中的,一个是子类内存区中的。所以子类对a赋值并不会影响到父类。
欢迎讨论

新手上路,请多包涵

老子在获得printA 这个技能的时候,连他将来有没有儿子都不知道,所以这个技能就是用的自己的a。
儿子并没有printA 这个技能,当被需要的时候,只能说让老子帮下忙。

不要过于纠结这个问题,这种写法在工程里是严格不允许的,编译工具不会报错,但是审查工具会报一个Blocker 等级的错误,Child class fields should not shadow parent class fields。

子类继承父类,但是并没有重写父类的printA方法,所以调用还是父类的printA方法打印9 而不是90

差不多就是1楼的意思,动态绑定和就近原则。调用的sup的printA所以this指的也是sup。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题