设计继承时,把共同的程序代码放入某个类,告诉其他类:此类是它们的父类
子类继承父类意味着继承了父类的成员,类的成员指的是实例变量和方法,但是子类可以加入自己的方法和实例变量,可以覆盖掉继承自父类的方法,实例变量不会被覆盖.
设计父类,辨别出所有子类共同的,抽象的特征,以此为基础设计.
当调用子类覆盖的父类方法时,会调用与该对象类型最接近的方法,即最低阶的会胜出,即层次树最下面.
继承关系通过IS-A检测,如老虎是个动物,老虎类继承自动物类.
X IS-A Y意味着X可以做任何Y可以做的事情.
通过super版的方法实现子类中仍然引用父类的方法再加上额外的行为
public void roam(){
super.roam();
//my own stuff
}
存取权限
private default protected public
从左到右限制程度越小
public类型成员会被继承
private类型成员不会继承
继承的意义
1.避免了重复的程序代码
2.定义出共同的协议(方法)
当你定义出一组类的父型时,你可以用字型的任何类来填补任何需要或期待父型的位置.
因为会通过声明为父型类型的 对象引用来引用它的子型对象
多态性
一般声明引用和创建对象的方法
Dog myDog=new Dog();
第一步要求JVM分配空间给引用变量myDog,此变量永远被固定为Dog类型
第二步要求JVM分配堆空间给新建立的Dog对象
第三步:将Dog赋值给引用变量myDog,即设定遥控器
由上可知引用变量类型与对象的类型必须相符
但在多态下,引用与对象类型可以不同
如
Animal myDog=new Dog();
运用多态时,引用类型可以是实际对象类型的父类
换句话说任何extends过声明引用变量类型的对象都可赋值给这个引用变量
举例如下
Animal[] animals=new Animal[2];
animals[0]=new Dog();
animals[1]=new Cat();
animals[2]=new Wolf();
for(int i=0;i<animals.length;i++){
animals[i].eat();
animals[i].roam();
}
当i=0,调用Dog的eat(),roam()其他同理.
不仅如此,参数和返回类型也可以多态,例如如果声明一个父类的引用变量,如animal,并赋值子类对象给它,如dog,则dog对象可当做方法参数(要求为animal对象)传入,则方法中相应的执行内容变为dog对象的执行内容
总结:
1.编写方法,将参数声明为父类类型,可以在运行时传入任何子类对象
2.防止特定的方法被覆盖,可以把该方法标识上final,将整个类标识为final,则表示没有任何方法可以被覆盖
3.有三个方法可以防止某个类作为父类
1)存取控制,类可以不标记为公有,非公有的类只能被同一个包的类做出子类
2)final修饰符表示继承树的末端,不可继承
3)只让类拥有private的构造程序
遵守合约:覆盖的规则
覆盖父类的方法,要遵守合约,如父类方法没有参数且返回布尔值,子类方法必须同样设置.方法就是合约的标志.
如父类:Appliance{boolean turnOn() boolean turnOff}
子类:Toaster {boolean turnOn(int level)}
对于turnOn(),这不是覆盖,因为改变了参数
编译器会寻找引用变量类型来决定是否可以调用该引用变量的特定方法,但在执行期JVM寻找的并不是引用变量类型,而是堆上的对象,因此若编译器同意这个调用,则唯一能通过的方法是覆盖的方法有相同的参数和返回类型.所以在运行期调用的还是父类的turnOn()方法,覆盖失败.
1.参数必须一样,且返回类型必须兼容
覆盖父类方法的子类一定要使用相同的参数,父类方法的返回类型是什么,子类要声明一样的类型或者该类型的子类.
2.不能降低方法的存取权限
存取权限必须相同,或者更加开放,不能覆盖掉一个公有的方法并将它标记为私有
方法的重载(overload)
重载是两个方法名称相同,但参数不同,重载与多态毫无关系
重载不是用来满足定义在父类的多态合约,重载方法比较有扩展性
1.返回类型可以不同
2.不能只改变返回类型
重载的条件是使用不同的参数
3.可以更改存取权限