.1.什么是继承?为什么要继承?
从字面意思上来看,继承是孩子从父母哪里继承得到的东西,或是徒弟从师傅哪里得到的技能或手艺。java中继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
还记得我们的DOTA英雄吗?
DOTA英雄可以攻击和释放技能,所以继承了它特性的天辉和夜魇英雄都可以攻击和释放技能,但天辉和夜魇英雄都可以拥有自己的独特属性和行为(方法)。
我们看到,无论是天辉还是夜魇英雄都有名字年龄种族和信仰的属性,都有攻击和释放技能的行为,但是天辉独有选举的方式产生领导者,而夜魇凭借的是力量上位,
那么我们就可以用extends关键字把它写成
dota英雄就是天辉和夜魇英雄的父类,天辉和夜魇英雄就是dota英雄的子类
注意:在java中,只允许单继承,也就是说 一个类最多只能显示地继承于一个父类。但是一个类却可以被多个类继承,也就是说一个类可以拥有多个子类。简单地说就是一个爹可以有多个孩子,但是一个孩子只能有一个爹(隔壁老王的微笑)
从上可以看到,父类存放共性,子类存放特性,所以它的作用是
1.解决了代码重复问题,提高代码的维护性和复用性。
2.更多的是表现出一个体系。
在Java中,除了object类,每一个类都有一个直接父类,object类是java语言的根类,也就是说object是老祖宗。
二、方法重写/覆盖
1.当在程序中通过对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
当调用自子类中的方法时,如果子类中没有这个方法,可以直接访问父类中的同名方法。
子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为override重写、复写或者覆盖。
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
2.方法覆盖的原则
① 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
private修饰的方法不能被子类所继承,也就不存在覆盖的概念
当父类方法大于访问权限大于子类,编译报错
②写法上必须一模一样:方法的返回值类型 方法名 参数列表都要一样。
注意:
1)只有方法有覆盖的概念,字段没有,方法覆盖解决了,父类的某一个行为不符合子类的特征,例如,鱼是鲸鱼的父类,鱼的呼吸行为是用鳃呼吸,而鲸鱼不是
2)对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
3)对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。
4)对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
5)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。
三、super关键字
1.重写后我们怎么去调用父类中的方法呢?
当我们重写后,用子类的某一方法去调用父类被重写后的方法时效果如下
这里其实在子类中skill()方法中默认的是 this.atack();
那我们怎么办呢?
用super关键字就可以访问父类中被重写的方法
四、子类初始化过程
即创建子类对象的过程
在创建子类对象之前会先创建父类对象,调用子类构造器之前,在子类构造器中会先调用父类的构造器,默认无参。
如果父类不存在可以被子类访问的构造器,则不能存在子类,也就是全是私有的,则不能有子类。
public static void main(String[] args) { //创建子类对象 TianHuiHero th=new TianHuiHero(); } class DotaHero { String name; int age; String race; String belive; //父类的无参构造,打印文字方便观察 public DotaHero() { System.out.println("倒不了的塔"); } } class TianHuiHero extends DotaHero { //子类的无参构造 public TianHuiHero() { //这里隐藏一个 super(); System.out.println("天辉胜利"); } }
执行打印,先调用了父类的构造函数,其实父类构造函数也有一个默认super()。
如果父类没有提供无参数的构造器,此时子类必须显示通过super语句,去调用父类带有参数的构造器。
父类无无参构造,而子类调用的是无参构造时,此时编译器报错。而通过显示super()语句来调用父类有参构造时程序可以编译执行。
public class JiCheng { public static void main(String[] args) { TianHuiHero th=new TianHuiHero("剑圣",45,"黄色"); } } class DotaHero { //当父类中的成员变量设为私有,创建子类时无法直接访问,所以需要调用父类的有参构造器间接访问。 private String name; private int age; String race; String belive; public DotaHero(String name,int age) { this.name=name; this.age=age; } } class TianHuiHero extends DotaHero { String color; public TianHuiHero(String name,int age,String color) { //调用父类构造,super必须作为第一句话 super(name,age); this.color=color; } }