head first Java第七章
继承
- 覆盖的意思是由子类重新定义继承下来的方法以改变或延伸此方法的行为
- 在设计继承时,你会把共同的程序代码放在某个类中,然后告诉其他的类说此类是它们的父类
- 当某个方法在子类中被覆盖过,调用这个方法时会调用到覆盖过的版本。
Java虚拟机会从继承关系树形图最下方开始搜索方法,不会出现没有找到方法的情况,因为编译器会保证引用特定的方法是一定能够被调用到,但在执行期它不会在乎该方法实际上是从哪个类找到的。要记得如果某个类继承了一个方法,它就会有那个方法。方法在哪里定义对于编译器来说不重要。但在执行期,Java虚拟机就是有办法找到正确的。
- 继承下来的方法可以被覆盖掉,但实例变量不能被覆盖掉。(实例变量无法被覆盖掉是因为不需要,它们并没有定义特殊的行为)
IS-A
IS-A三角形是一个(继承关系)多边形
HAS-A浴室有一个(不是继承关系)浴盆
IS-A测试适用在继承层次的任何地方。如果你的继承层次树设计得很好,那么所有的子类都应该通过任一个上层父类的IS-A测试
如果类Y是继承类X,且类Y是类Z的父类,那么Z应该能通过IS-A X的测试
注意:继承概念下的IS-A是个单向的关系
X IS-A Y隐喻着X可以做出任何Y可以做的事情(且还可能会做出更多的行为)
如果在子类中还打算引用父类的方法然后再加上额外的行为应该怎么办?
这是可行的!事实上这个功能非常重要。扩充本来就有扩充和延伸的意思。
public void roam(){
super.roam();//这会先执行super版的roam()
//my own roam stuff 然后再回来执行自定义的行为或功能
}
你可以在父类中设计出所有子类都使用的功能实现。让子类可以不用完全覆盖掉父类的功能,只是再加上额外的行为。你可以通过super这个关键词来取用父类。
存取权限
private
` default
protected
public`(左边是最受限制的,而越往右边限制程度越小)
-
public
类型的成员会被继承 -
private
类型的成员不会被继承
继承让你可以确保某个父型之下的所有类都会有父型所持有的全部方法(全部可继承的方法)
也就是说,你会通过继承来定义相关类间的共同协议
当你在父类中定义方法时,它们会被子类继承,这样你就是在对其他程序代码表明:“我的所有子类(例如说subclass)都能用这些方法来执行这几项工作……”
多态
运用多态时,引用类型可以是实际对象类型的父类
Animal[] animals = new Animal[5];//声明Animal类型的数组。也就是说一个会保存Animal类型对象的数组
animals[0] = new Dog();//但是注意到这边……你可以放任何Animal的子类对象进去
animals[1] = new Cat();
animals[2] = new Wolf();
animals[3] = new Hippo();
animals[4] = new Lion();
for(int i = 0;i < animals.length;i++){//这就是多态最强的地方,你可以将数组元素逐个调出来当做是Animal来操作
animals[i].eat();//当i为0时,这会调用Dog的ead()
animals[i].roam();//当i为1时,这会调用Cat的roam()
}
不仅如此,参数和返回类型也可以多态
class Vet{
public void giveshot(Animal a){//a参数可以用任何Animal的类型对象来当传入。
//射爆这个动物
a.makeNoise();//执行到makeNoise()的时候,不管它引用的对象到底是什么,该对象都会执行makeNoise()
}
}
class PetOwner{
public void start(){
Vet t = new Vet();
Dog d = new Dog();//giveShot这个方法可以取用用任何一种Animal
Hippo h = new Hippo();//只要所传入的是Animal的子类它都能执行
v.giveShot(d);//会执行Dog的makeNoise()
v.giveShot(h);//会执行Hippo的makeNoise()
}
}
通过多态,你就可以编写出引用新型子类时也不必修改的程序
你能够继承任何一个类吗?就像类的成员一样如果类是私有的你就不能继承?
除了内部类之外,并没有私有类这样的概念。但是有三种方法可以防止某个类被作出子类
- 第一种是存取控制。就算类不能标记为私有,但它还是可以不标记为公有。非公有的类只能被同一个包的类做出子类
- 第二种是使用
final
这个修饰符(modifier
)。这是表示它是继承树的末端,不能被继承。
- 第三种是让类拥有private的构造程序(
constructor
)
你为什么会做出表示final
的类?这样有什么好处?
一般来说,你不会标识
final
。但如果你需要安全——确保方法都会是你写的版本,此时就需要final
可不可以只用final
去标识方法而不使用整个类?
如果你想要防止特定的方法被覆盖,可以将该方法标识上
final
这个修饰符。将整个类标识成final
表示没有任何的方法可以被覆盖。
覆盖的规则
- 参数必须要一样,且返回类型必须要兼容
例如父类中有boolean turnOn()这个方法,子类中又写了boolean turnOn(int level)这个方法,这里子类的方法改变了方法的参数,是一个合法的重载,但这不是覆盖。
父类的合约定义出其他的程序代码要如何来使用方法
- 不能降低方法的存取权限
例如父类中有public boolean turnOn()这个方法,子类中又写了private boolean turnOn()这个方法,这样写不合法,因为改变了存取权限
这代表存取权必须相同,或者更为开放。
重载
重载的意义是两个方法的名称相同,但参数不同。所以,重载和多态毫无关系。重载的方法与覆盖方法不一样
-
返回类型可以不同
-
不能只改变返回类型
如果只有返回类型不同,但参数一样,这是不允许的。
- 可以更改存取权限
李晓晗
更新于2019-8-1 下午