JAVA基础篇--面向对象之继承
子类继承父类,将获得父类的全部成员变量和方法,需要注意的是不能获得父类的构造器。这里有个疑惑,子类能不能获得父类中私有属性(包括变量和方法)?我也不清楚。
继承变量和方法
实例(static修饰)和实例变量两种。子类继承父类变量时,如果在子类中定义了同名的变量(可以不同类型),父类中的变量会被覆盖,无论是类变量还是实例变量。需要注意,覆盖并不是指父类中的变量不存在了,可以通过super关键字来访问父类变量就知道父类变量并没有消失。子类 中没有与父类中有同名变量时,父类中的类变量会被子类继承成为自己的类变量。例如,父类Base有一个static变量i,这个变量i会被子类继承,这时,子类和父类均有一个static变量i。同样,父类中的实例变量被子类继承成实例变量。
子类对父类方法的继承和对变量的继承道理是一样的,就不再重复了。
方法重写
变量的覆盖较好理解,上面也介绍了。方法的重写(也叫覆盖)稍微复杂一些。子类包含有父类同名方法的现象叫方法重写,往下看。
1.方法重写遵循“两同两大一小”规则。“两同”指方法名,形参列表相同;“两大”指子类方法返回值类型比父类方法返回值类型更小或相等,子类方法声明抛出的异常比父类方法声明抛出的异常更小或相等,“一大”指子类方法的访问权限比父类方法的访问权限更大或相等。
2.覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法。不能一个是类方法,一个是实例方法,否则会编译错误。
3.子类覆盖了父类方法后,子类对象无法访问父类中被覆盖的方法,但可以调用父类中被覆盖的方法。通过使用super(覆盖的是实例方法)和父类类名(覆盖的是类方法)作为调用者来调用父类被覆盖的方法。
4.如果父类方法具有private权限,子类无法访问改方法,也就是无法重写该方法。如果子类中定义了一个与父类private方法具有相同的方法名,形参列表,相同的返回值类型的方法,这不是重写,只是在子类中重新定义了一个新方法。
super关键字限定
在子类中调用父类被覆盖的实例方法或变量,可以使用super限定字。super用于限定子类对象调用它从父类继承得到的实例变量和方法,和this关键字一样,super不能出现在static修饰的方法中,原因就不用说了。
super关键字还可以用来调用父类构造器的初始化代码,类似于用this关键字调用重载构造器。super调用和this调用都必须出现在构造器执行体的第一行,所以,this调用和super调用不会同时出现。
继承时构造器的执行顺序
先说结论:父类构造器是一定先于子类构造器执行的。
首先,子类构造器调用父类构造器有几种情况:
1.子类构造器super显示调用父类构造器,系统根据super调用参数调用父类相应构造器;
2.子类构造器this显示调用本类中重载的构造器,系统根据this调用执行本类中另一个构造器。执行本类中另一个构造器时即会调用父类构造器。
3.子类构造器既无super调用也无this调用,系统在执行子类构造器之前隐式调用父类无参数的构造器;
可以不用硬记这三种,可以这么记。在子类构造器中有两种方式,一是用super关键字显式调用父类的构造器,二是没有super关键字隐式调用。
如果是显式调用,系统会根据super调用的参数来查找父类中有没有相应的构造器,如果没有,编译错误,有则调用。
这些自定义构造器中要是没有无参数构造器,出现编译错误。
总结一下就是:子类中有没有super显示调用父类构造器,有,则调用相应父类构造器;无,则调用父类无参数的构造器。如果系统找不到要调用的父类构造器,编译错误。可以这么理解,在执行子类构造器时,第一行总是会执行super()来调用父类构造器。
所以,创建任何对象时都是从该类继承树最顶端的构造器,也就是Object类的构造器开始执行,然后依次向下执行,最后才是本类的构造器。
注意:一个类中如果没有构造器,系统会默认提供一个无参数的构造器;如果在类中定义了构造器(不管这个构造器有无参数),则系统就不会再提供一个无参数的构造器。
还注意:初始化块在构造器之前被执行。实际上初始化块是一个假象,使用javac命令编译Java类后,该Java类中的初始化块会消失——初始化块中代码会被“还原”到每个构造器中,且位于构造器所有代码的前面。