继承的基本语法
(1)当sub类和base类位于同一包中:sub类继承base类中的pulic、protected和默认访问级别的成员变量和成员方法。
当sub类和base类位于不同包中时:sub类继承base类中的public、protected访问级别的成员变量和成员方法。
(2)Java不支持多继承。
(3)所有的Java类都直接或间接地继承了java.lang.Object,假如在定义一个类时,没有使用extends关键字,那么这个类直接继承Object类。

方法重载
(1)对于类的方法(包括从父类中继承的方法),如果有两个方法的方法名相同,但参数不一致,那么可以说,一个方法是另一个方法的重载,重载方法必须满足以下条件:
A)方法相同。
B)方法的参数类型、个数、顺序至少有一项不同。
C)方法的返回类型可以不相同。
D)方法的修饰符可以不相同。
(2)一个类中不允许定义两个方法名相同,并且参数签名(即使返回类型或修饰符不同)也完全相同的方法。

(3)隐藏:C++中,在基类和派生类中使用同一名字的成员函数,在派生类作用域中的派生类成员将屏蔽基类成员,即使函数原型不同,基类成员也会被屏蔽,而Java中则不会。

 

 方法覆盖

(1)如果在子类中定义的一个方法,其名称、返回类型及参数签名正好与父类中某个方法的名称、返回类型及参数签名相匹配,那么可以说,子类的方法覆盖了父类的方法。
(1)子类方法的名称、参数签名和返回类型必须与父类方法的名称、参数签名和返回类型一致,Java编译器首先判断sub类的method方法与base类的method方法的参数签名,由于两者一致,因此java编译器认为sub类的method方法试图覆盖父类的方法,既然如此,sub类的method方法就必须和被覆盖的方法具有相同的返回类型。(编译错误)
 
(2)子类方法不能缩小父类方法的访问权限,假如父类的方法是公有的,当Java虚拟机调用base变量(引用类型为Base)所引用的sub实例的method方法,如果子类的method()方法是私有的,Java虚拟机就无法访问它。(编译错误)
(3)子类方法不能抛出比父类方法更多的异常,子类方法抛出的异常与父类方法抛出的异常相同,或者子类方法抛出的异常类是父类方法抛出的异常类的子类(只能二者选其一)。
(4)方法覆盖只存在与子类和父类之间(包括直接父类和间接父类),在同一个类方法中只能被重载,不能被覆盖。
(5)父类的静态方法不能被子类覆盖为非静态方法。
(6)子类可以定义与父类的静态方法同名的静态方法,以便在子类中隐藏父类的静态方法,在编译时,子类定义的静态方法也必须满足与方法覆盖类似的约束。
子类隐藏父类的静态方法和子类覆盖父类的实例方法,两者的区别在于:运行时,Java虚拟机把静态方法和所属的类绑定,而把实例方法和所属的实例绑定。
(7)父类的非静态方法不能被子类覆盖为静态方法。
(8)父类的私有方法不能被子类覆盖。由于print方法在base类中定义,因此print方法会调用在base类中定义的private类型的method方法。但如果把base类的showMe()方法改为public,尽管print()是在base类中定义,java虚拟机还是会调用当前sub实例的showMe()方法。
(9)父类的抽象方法可以被子类通过两种途径覆盖:一是子类实现父类的抽象方法;二是子类重新声明父类的抽象方法(仅仅扩大访问权限,但不能缩小访问权限)。
(10)父类的非抽象方法可以被覆盖为抽象方法。

 

 方法覆盖与方法重载的异同

方法重载和方法覆盖有以下相同点:
(1)都要求方法名同名。
(2)都可以用于抽象方法和非抽象方法之间。
方法重载和方法覆盖有以下不同点:
(1)方法重载要求参数签名必须不一致,方法覆盖要求参数签名必须一致。
(2)方法重载对返回类型不做要求,方法覆盖要求返回类型必须一致。
(3)方法重载用于同一类的所有方法(包括从父类中继承而来的方法),方法覆盖只能用于子类覆盖父类的方法。
(4)方法覆盖对方法的访问权限和抛出的异常有特殊的要求。
(5)一个方法在所在的类可以被重载多次,父类的一个方法只能被子类覆盖一次。

 super关键字
(1)以下场合会出现方法或变量被屏蔽的现象:
A)在一个方法内,当局部变量和类的成员变量同名,或者局部变量和父类的成员变量同名,只有局部变量在方法内可见。
B)当子类的某个方法覆盖了父类的一个方法,在子类的范围内,父类的方法不可见。
C)当子类定义了和父类同名的成员变量时,在子类的范围内,父类的成员变量不可见。
(2)在以下情况下会使用super关键字
A)在类的构造方法中,通过super语句调用这个类的父类的构造方法。
B)在子类中访问父类的被屏蔽的方法和属性。
(3)如果父类中的成员变量和方法被定义为private,那么子类永远无法访问它。
(4)只能在构造方法或实例方法内使用super关键字,不能在静态方法和静态代码块内部使用super关键字。

多态
(1)如果把引用变量转换为子类类型,则称为向下转型;如果把引用变量转换为父类类型,则称为向上转型。
(2)通过引用变量访问它所引用的实例的静态属性、静态方法、实例属性、实例方法以及从父类中继承的方法和属性时,Java虚拟机会采用不同的绑定机制。
(1)对于一个引用类型的变量,Java编译器按照它声明的类型来处理。
(2)对于向上转型,不必使用强制类型转换,因为子类的对象肯定也可看作父类的对象;对于向下转型,必须进行强制类型转换;如果两种类型之间没有继承关系,编译器不允许进行类型转换。
(3)对于一个引用类型的变量,运行时Java虚拟机按照它实际引用的对象来处理。例如,下面的代码虽然可以编译通过,但会抛出ClassCastException异常。
(4)在运行环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则:
A)实例方法与引用变量实际引用的对象的方法绑定,属于动态绑定,因为是在运行时由Java虚拟机动态决定的。
B)静态方法与引用变量所声明的类型的方法绑定,属于静态绑定,在编译阶段完成。
C)成员变量(包括静态变量和实例变量)与引用变量所声明的类型的成员变量绑定,属于静态绑定,在编译阶段完成。
(5)动态绑定:在运行时环境中,当通过B类的实例去调用一系列的实例方法(包括一个方法调用另一个方法),将优先和B类本身包含的实例方法动态绑定,如果B类没有定义这个实例方法,才会与从父类A中继承来的实例方法动态绑定。

 继承的利弊和使用原则
(1)继承树的层次不可太多。
(2)继承树的上层为抽象层
A)当一个系统使用一棵继承树上的类时,应该尽可能地把引用变量声明为继承树的上层类型,这可以提高两个系统之间的耦合度。
B)如果继承树上有接口类型,那么应该尽可能地把引用变量声明为继承树上层的接口类型。
C)在设计继承树时,首先进行自下而上的抽象,即识别子类之间所拥有的共同属性,然后抽象出共同的父类,位于继承树最上层的父类描述系统对外提供哪些服务。如果某种服务的实现适用于所有子类或者大多数子类,那么在父类中就实现这种服务。如果某种服务的实现方式取决于各个子类的特定属性和实现细节,那么在父类中无法实现这种服务,只能把代表这种服务的方法定义为抽象方法,并且把父类定义为抽象类。
(3)继承关系最大的弱点:打破封装
在继承关系中,子类能够访问父类的属性和方法,也就是说,子类会访问父类的实现细节,子类与父类之间是紧密耦合关系,当父类的实现发生变化时,子类的实现也不得不随之变化,这消弱了子类的独立性。
(4)精心设计专门用于被继承的类
A)对这些类必须提供良好的文档说明。
B)尽可能地封装父类的实现细节,也就是把实现细节的属性和方法定义为private类型。如果某些实现细节必须被子类访问,可以在父类中把包含这种实现细节的方法定义为protected类型。当子类仅调用父类的protected类型的方法,而不覆盖它时,可把这种protected类型的方法看做父类仅向子类但不对外部公开的接口。
C)把不允许子类覆盖的方法定义为final类型。
D)父类的构造方法不允许调用可被子类覆盖的方法。
(5)如果某些类不是专门为了继承而设计,那么可以采用两种措施来禁止继承:
A)把类声明为final类型。
B)把这个类的所有构造方法声明为private类型,然后通过一些静态方法来负责构造自身的实例。
(5)区分对象的属性和继承

 比较组合和继承
 组合关系的分解过程对应继承关系的抽象过程
(1)UML中的关联关系和聚集关系统称为组合关系。
(2)对于组合关系,创建整体类的实例时,必须创建其所有局部类的实例;而对于继承关系,创建子类的实例时,无需创建父类的实例。
组合关系的组合过程对应继承关系的扩展过程