Java学习总结之第五章 继承
一、继承的基本语法
1、在Java语言中,用extends关键字来表示一个类继承了另一个类。
2、Java语言不支持多继承,一个类只能直接继承一个类,但它可以有多个间接的父类。
3、所有的Java类都直接或间接地继承了java.lang.Object类。如果在定义一个类时,没有使用extends关键字,那么这个类直接继承Object类。
二、方法重载
重载方法必须满足以下条件:
l 方法名相同。
l 方法的参数签名(即参数类型、个数、顺序)中至少有一项是不相同的。
l 方法的返回类型可以不相同。
l 方法的修饰符可以不相同。
三、方法覆盖
覆盖方法必须满足以下约束条件:
l 子类方法的名称、参数签名和返回类型必须与父类方法的名称、参数签名和返回类型一致。
l 子类方法不能缩小父类方法的访问权限。
l 子类方法不能抛出比父类方法更多的异常。子类方法抛出的异常必须和父类方法抛出的异常相同,或者子类方法抛出的异常类是父类方法抛出的异常类的子类。
l 方法覆盖只存在于子类和父类(包括直接父类和间接父类)之间。在同一个类中方法只能被重载,不能被覆盖。
l 父类的静态方法不能被子类覆盖为非静态方法,但子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法。注意:在此处是隐藏父类的静态方法,而不是覆盖。子类隐藏父类的静态方法和子类覆盖父类的实例方法这两者的区别在于:运行时,Java虚拟机把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。以下为演示代码:
class Base{ void method(){ //实例方法 System.out.println("method of Base"); } static void staticMethod(){ //静态方法 System.out.println("static method of Base"); } } public class Sub extends Base{ void method(){ //覆盖父类的实例方法method() System.out.println("method of Sub"); } static void staticMethod(){ //隐藏父类的静态方法staticMethod() System.out.println("static method of Sub"); } public static void main(String[] args) { Base sub1 = new Sub(); //sub1变量被声明为Base类型,引用 Sub实例 sub1.method(); //打印 method of Sub sub1.staticMethod(); //打印 static method of Base Sub sub2 = new Sub(); //sub2变量被声明为Sub类型,引用Sub实例 sub2.method(); //打印 method of Sub sub2.staticMethod(); //打印 static method of Sub } } |
l 父类的非静态方法不能被子类覆盖为静态方法。
l 父类的私有方法不能被子类覆盖。以下为演示代码:
class Base{ private String showMe(){ return "Base"; } public void print(){ System.out.println(showMe());//到底调用父类的还是Sub类showMe()? } } public class Sub extends Base{ public String showMe(){ return "Sub"; } public static void main(String[] args) { Sub sub = new Sub(); sub.print(); } } 打印结果为”Base”,这是因为print()在Base类中定义,因此print()方法会调用在Base类中定义的private类型的shoeMe()方法。 如果把Base类的showMe()方法改为public类型,其他代码不变: class Base{ public String showMe(){ return "Base"; } … } 此时打印出的结果为”Sub”,这是因为此时Sub类的showMe()方法覆盖了Base类的showMe()方法。因此尽管print()方法在Base类中定义,Java虚拟机还是会调用当前Sub实例的showMe()方法。 |
l 父类的抽象方法可以被子类通过两种途径覆盖:一是子类实现父类的抽象方法;二是子类重新声明父类的抽象方法。
l 父类的非抽象方法可以被覆盖为抽象方法。
四、super关键字
1、在以下情况中会使用super关键字:
l 在类的构造方法中,通过super语句调用这个类的父类的构造方法。
l 在子类中访问父类的被屏蔽的方法和属性。
2、只能在构造实例方法内使用super关键字,而在静态方法和静态代码块内不能使用super关键字。
五、多态
1、对于一个引用类型的变量,Java编译器按照它声明的类型来处理。Java编译器允许在具有直接或间接继承关系的类这间进行类型转换,对于向上转型(即把引用变量转换为父类类型),不必使用强制类型转换,而对于向下转型(即把引用变量转换为子类类型),则必须进行强制类型转换。
2、对于一个引用类型的变量,运行时,Java虚拟机按照它实际引用的对象来处理。
3、在运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则:(非常重要!!!)
l 实例方法与引用变量实际引用的对象的方法绑定,这种绑定称为动态绑定,因为是在运行时由Java虚拟机动态决定的。
l 静态方法与引用变量所声明的类型的方法绑定,这种绑定称为静态绑定,因为实际上是在编译阶段就已经做了绑定。
l 成员变量(包括静态变量和实例变量)与引用对象所声明的类型的成员变量绑定,这种绑定属于静态绑定,因为实际上是在编译阶段就已经做了绑定。
4、动态绑定的思想:在运行时环境中,当通过B类的实例去调用一系列的实例方法(包括一个方法调用
的另一个方法),将优先和B类本身包含的实例方法动态绑定,如果B类没有定义这个实例方法,才会与从父类A中继承来的实例方法动态绑定。
六、继承的使用原则
1、继承树(不考虑顶层的Object类)的层次应该尽量保持在两到三层。
2、当一个系统使用一棵继承树上的类时,应该尽可能地把引用变量声明为继承树的上层类型,这可以提高两个系统的松耦合。如果继承树上有接口类型,那么应该尽可能地把引用变量声明为继承树上层的接口类型。
3、应该把不允许子类覆盖的方法定义为final类型。