1. 类的继承:
1) Java使用extends关键字来继承一个类,例如:public class Son extends Father { ... }表示Son类继承Father类;
2) Java不支持C++非常麻烦的多继承,即extends只能继承一个父类;
3) Java使用extends来表示继承,从词义来看继承也是一种对父类的扩展,即子类可以获得父类的全部数据和方法(只不过有些对子类可见,有些不可见,要看父类中成员的访问控制符是什么,即使不可见也是用于父类的全部属性的,就是用不了(访问不了)而已),并且在此基础上还可以定义自己新增的数据和方法;
2. 覆盖(重写)父类的方法:
1) 子类可以通过重写(覆盖)父类的方法达到多态的目的(多态的概念下一章会详细介绍);
2) 覆盖的原则必须要遵循“三同两小一大”:
i. 三同:
a. 方法名相同;
b. 形参列表相同;
c. 覆盖的方法要和子类方法一样,要么都是静态的,要么都是非静态的,不能不一致,不一致会直接编译报错!
!!总结来说就是方法签名相同;
ii. 两小:
a. 子类方法的返回值类型要比父类方法返回值类型的范围更小或者相等;(如果更小就是返回类型协变)
b. 子类方法抛出的异常的类型要比父类方法抛出的异常类型范围更小或者相等;
!!这在类型上是兼容的,可以理解为范围小的类型是范围大的类型的子类族,刚好向上兼容!
iii. 一大:子类覆盖方法的访问控制符应该比父类的更大;
!!从大到小是:public -> protected -> default -> private
3) 只要符合“三同两小一大”原则的都会触发“覆盖(重写)”,这样Java编译器会把子类的该方法当成“覆盖”方法,将具备多态功能!只要上面的原则有一点不符,该方法就会被当做一个普通方法(或者是其它重载方法),不具备多态的特性;
!!再次强调,如果符合“两同两小一大”,但一个是静态一个是非静态(差一同),就会编译报错!千万要小心,静态属性必须相同;
4) 特殊情况:子类无法覆盖父类的private方法
i. 由于父类的private方法对于子类来说也是不可见的;
ii. 既然子类不可见,那子类就会当完全没有这个方法;
iii. 因此如果子类还是强行覆盖该方法(访问控制符可以是任意一种,都是大于等于private的),那也不会形成覆盖!Java会把它当成一个属于子类的新方法;
!!因此private限定符要跟就不是用来覆盖的(继承、多态),仅仅表示这是一样非常私人的东西,谁都不能看见,包括自己的儿子;
小结:因此,对于父类中的private方法(静态、非静态)根本就不再“三同两小一大”的体系当中,因此子类中可以肆无忌惮地写和该方法同方法签名的方法,即使一个是静态的一个是非静态的也行,毕竟父类的private的方法子类是当完全不存在的!!
3. 用super限定符来访问父类:
1) 从父类中继承来的变量和方法是可以在子类中直接使用的(只要不是private的就行),比如从父类继承了一个int a,那么可以直接在子类中访问(使用)它,比如a + 5之类的直接用变量名来访问;
2) 但如果子类自己的变量或方法和父类继承来的重名,那么对于变量会隐藏父类的变量(变量不会覆盖,父类子类各一份),对于方法也许会覆盖(如果符合“三同两小一大”的条件),这是因为在对象中所有对对象数据和方法的访问默认使用this.引导的,而this默认指代的是当前对象(this的类型是运行时类型),即子类对象,因此如果发生重名或覆盖,则调用的是子类的变量和方法(覆盖方法);
!!但有时又有想要调用父类继承的变量和方法的需求,这时就可以使用super限定符来访问父类部分了;
3) 和this引用一样,super也是引用:
i. this代表当前对象的引用,而super代表当前对象的父类部分的引用;
ii. this的运行时类型是子类,而super的运行时类型是父类,因此super只能访问父类部分,this可以访问整个子类(子类也包含父类),而如果发生重名或覆盖,用super来访问被覆盖和被重名的部分再合适不过了;
iii. 例如:super.a(访问父类被重名的数据)、super.func()(访问父类被覆盖的方法);
4) super和this一样,都是非静态的,都是指代具体的对象,因此不能在静态方法和静态块中使用super限定符;
5) super并不是只有在重名或覆盖的时候才可以用super,任何情况下都可以用super限定来访问父类部分;
6) Java定位一个不加任何限定符的变量的顺序(例如一个变量a):是否是局部变量? -> 是否是子类的变量? -> 是否是父类的变量? -> 一直追溯到Object;
7) 由于super和this一样都指代对象,因此也可以用super来访问父类的静态变量,但这样做是不符合逻辑,尽量不要这样使用,还是用父类的类名来访问父类的静态变量;
8) 也可以不使用super强行访问父类部分:
i. 就是利用向上转型的原理,向上转型是类型兼容的;
ii. 例如:Father类有一个a变量,Son也有一个自己定义的a,现在Son的对象是s,那么就可以这样访问父类部分的a,((Father)s).a;
!!即先对子类对象向上转型,转型后,运行时类型就变成父类了,这样就只有父类部分是可见的,因此访问的a也是父类部分的a;