继承:
概念:
- 继承父类的属性和行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
- 继承是多态的前提,如果没有继承,就没有多态。
特点:
- java只能单继承,但可以多层继承(a继承b,b继承c,那么a就有b和c的属性)
- 老师和学生是人的一种,那么人就是父类,老师学生就是子类(谁是谁的一种)
- 为什么不支持多继承?
如果是a同时继承b和c,而且b和c都有一个method方法,那a会懵逼,它不知道用哪个,为了不让它懵逼,所以不能多继承,但是可以多层继承,因为有就近原则
格式:
class 子类 extends 父类 {...}
// Java是单继承的。一个类智能继承一个类(一个人只有一个亲生父母)
好处:
1.提高代码的复用性(相同的代码不需要重复的写,只需要提取到父类中,子类可以直接使用)
2.提高代码的维护性
弊端:
- 耦合性(代码与代码之间存在关联就是耦合)
- 降低代码的灵活性(继承了以后子类必须拥有父类的非私有属性和方法,子类会被约束)
就近原则:
在子类方法中访问一个变量,采用的是就近原则,先看自己有没有,没有就找爸爸要
- 整个流程是这样:
子类局部范围找
子类成员范围找
父类成员范围找
如果都没有就报错(不考虑父亲的父亲…)
使用场景:
类与类之间存在相同(共性)的内容,就可以使用继承优化代码。
比如iPhone是一个手机品牌,huawei是一个手机品牌,Samsung也是一个手机品牌,但都有一个共性就是手机,所以就都可以继承手机类
案例:
学生类:
- 属性:姓名、年龄、学习、吃饭、睡觉;
老师类:
- 属性:姓名、年龄、教书、吃饭、睡觉;
班主任类
- 属性:姓名、年龄、管理、吃饭、睡觉;
思路:
共同拥有的属性抽取到父类,子类只需要继承父类就可以得到这些属性、方法,子类只需要写子类特有的方法即可。
// 定义父类
public class Human {private String name;private int age;public void eat(){System.out.println("我是父类的吃方法");}public void sleep(){System.out.println("我是父类的睡觉方法");}// 省略get、set、构造方法}// 定义学生类
public class Student extends Human {public void study(){System.out.println("我是学生类的上课方法");}// 定义老师类
public class Teacher extends Human {
public void teach(){System.out.println("我是老师类的上课方法");}}
}// 定义班主任类
public class ClassTeach extends Human{public void manage(){System.out.println("我是班主任类的管理方法");}
}// 定义测试类public static void main(String[] args) {Teacher teacher = new Teacher();teacher.eat();teacher.sleep();teacher.teach();teacher.setAge(21);teacher.setName("小明");System.out.println(teacher);}
}
得到结果:
注意:
子类不能继承父类的构造器,因为子类有自己的构造器。
但是子类可以继承父类的私有成员(成员变量,方法),只是子类无法直接访问而已,可以通过getter/setter方法访问父类的private成员变量。
super:
概念:
this:代表本类对象的引用
super:代表父类存储空间的标识(可以理解为父类对象引用)
this和super的使用区别:
成员变量:
- this.成员变量 – 访问本类成员变量
- super.成员变量 – 访问父类成员变量
成员方法:
- this.成员方法 – 访问本类成员方法
- super.成员方法 – 访问父类成员方法
构造方法:
- this(…) – 访问本类构造方法
- super(…) – 访问父类构造方法
继承中构造方法的访问特点:
通过子类对象访问一个方法
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲…)
问题:
- 子类继承父类出现重名的成员变量时会有变化吗?
子类继承父类后,出现重名的成员变量,子类会优先访问自己的,自己没有才去访问父类的- 子类中所有的构造方法默认都会访问父类中无参的构造方法
- 为什么要把super()放在第一行
- 子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化, 原因在于,子类构造器的第一行都隐含了一个super()去调用父类的无参构造器,super()可以省略不写。
- 如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
- 通过使用super关键字去显示的调用父类的带参构造方法
- 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法
注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存,默认的super();也是在第一行的,只是隐式的而已。