当创建java实例对象时,程序总会先依次调用每个父类的非静态代码块、父类构造器(总是从Object开始)执行初始化,最后才调用本类的非静态代码块、构造器进行初始化。而父类构造器的调用则取决于子类的显示调用(使用super关键字调用父类构造器)或隐式调用(没有使用super或者this则默认调用父类的无参构造器)。
Person p = new Son();(Person是son的父类,person即p的声明类型,son则为p的实际类型)
不管声明一个变量用的是什么类型,当通过这些变量调用方法时,方法的行为总是表现出他们实际类型的行为;但如果通过这些变量来访问他们所指对象的实例变量时,则这些实例变量的值总是由声明这些变量的用类型来决定。(如果子类重写了父类的方法,就意味着子类的方法彻底覆盖了父类的同名方法,而对于实例变量则不一样,即使在子类中定义了与父类完全同名的实例变量,这个实例变量仍然不可能覆盖父类中定义的实例变量,这就是继承成员变量和继承方法之间的差别)
当子类使用public访问修饰符修饰,而父类不使用public修饰时,才可以通过javap看到编译器将父类的public方法直接转移到子类中去(子类没有重写父类的该方法)
子类中访问父类静态方法或静态变量的方式:
1.通过父类名.变量名/方法名进行调用
2.构造器中通过super关键字来进行调用
从语法角度来看,程序可以在3个地方对实例变量执行初始化:
1.定义实例变量时指定初始值
2.非静态初始化块中对实例变量指定初始值
3.构造器中对实例变量指定初始值
注意:以上三种方式的执行顺序是 1和2的执行顺序比3更早,而1和2的执行顺序则和它们在源码中的顺序相同
从语法角度来看,程序可以在3个地方对类变量执行初始化:
1.定义类变量时指定初始值
2.静态初始化块中对类变量指定初始值
注意:以上两种方式的执行顺序是 1和2的执行顺序和它们在源码中的顺序相同
如果父类构造器调用了被子类重写的方法,且通过子类构造器来创建子类对象,在父类构造器中调用了这个方法,这就会导致子类重写的方法会在子类构造器的代码之前被执行,从而导致该方法访问不到子类实例变量的值
关于继承,子类的实例对象不仅保存了本类中定义的所有实力变量,还保存了它的父类所定义的全部实力变量(包括重名的)
通过子类调用父类的构造器时,如果在父类的构造器中使用了this,则this指向的是子类的对象,而不是父类的