新手问一个很奇怪的问题

class Demo {
int num = 1;
int add = 2;
Demo() {
num = 5;
add = 6;
}
void show() {
System.out.println("Fu num="+num+" Fu add="+add);
}
}

class DemoA extends Demo {
DemoA() {
this.num = 3;
this.add = 4;
}

void show() {
    System.out.println("Zi show");
    System.out.println("Zi.num="+this.num+" Zi.add="+this.add+" Fu.num="+super.num+" Fu.add="+super.add);
}

}

class test1 {
public static void main(String[] args) {
DemoA d = new DemoA();
d.show();
Demo d1 = new Demo();
d1.show();
}
}

这个程序中为什么DemoA中的show()方法输出的super.add是4呢?

因为父类没加修饰符,默认是friendly,允许同一个包内的其他类访问和修改。

补充一下,也就是对你这段代码来说,父类的add相当于公共变量,子类重新赋值就改变了值。

子类中add与父类中add实际是一样的,你的子类构造函数重写了父类的构造函数,相当于先把add赋值成了5然后子类构造函数又赋值成了4

子类在创建对象时会调用父类的构造方法(前提是父类存在无参构造方法)在创建子类时,父类将add赋值为5,子类又将add赋值为4,所以add的值就变成4了,所以在调用父类属性时add变成了4.

因为修改子类中的num,add实际是修改了父类中的num,add,所以输出的是4

如果你在子类中同样定义了num,add,那么在子类对这两个变量进行赋值,只是修改的是子类中的变量,这是super.num,super.add就是输出的是父类中的num,add的值了

因为生成子类之前会先生成父类,所以这里首先运行了父类(Demo)的构造方法,然后再运行子类(DemoA)的构造方法,所以super.add最后一次的赋值为4,也就是this.add=4。因为这里父子类add属性只存在一个,而且父类的add 不是私有的(private),所以它们共用一个add属性,也就是super.add和this.add其实是一样的。

这个可以查看下class文件的字节码,具体可以通过javap查看Demo.class和DemoA.class的字节码中常量池(命令格式:javap -v 类文件.class)。
变量add和num是在父类Demo中,即为Demo.add和Demo.num。
通过this.add和super.add都会访问到Demo.add,num变量同理

子类继承了父类的非final的方法和属性,在初始化的时候先执行父类的构造函数,在执行子类的构造函数。由于继承了父类的属性,子类继承属性不会在开辟新的内存空间