7. 继承
人属于动物,猪属于动物,等等等……
我们先来模拟几样东西:Student类,Employee类,Person类
//人 类
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//学生 类
class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private int studentID;
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
this.studentID = studentID;
}
}
//职工 类
class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
我们发现,学生与职工本来就属于人,并且在源代码中存在大量的重复代码。
如果没有继承,类和类的关系将无法描述,就像学生与人的关系一样。。。
继承特点:
1:描述类和类之间的关系
2:降低类和类之间的重复代码
3:降低对象和对象之间的代码重复使用静态变量
4:降低类和类之间的代码重复使用
所以,我们要用一个关键字来描述继承关系:
extends:描述继承关系的关键字
学生继承人,发现学生里的“姓名”属性,在人的class里也都进行了定义。
所以我们可以写成这种形式:
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person {
private int studentID;
public int getStudentID() {
return studentID;
}
public void setStudentID(int studentID) {
this.studentID = studentID;
}
}
Java只支持单继承!!!
1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类
2:子类并不能继承父类中所有的成员
2.1:父类定义完整的成员(静态成员,非静态,静态变量和静态方法)都可以通过
子类名.父类静态成员 的形式调用成功。
2.2:所有的私有成员不能继承(private修饰的成员)
2.3:构造方法不能被继承
3:不要为了使用继承而继承。职工和学生都有共性的成员,不要为了节省代码,让职工继承学生,那样会显得没有逻辑并且关系也就描述不过去了。。。
super关键字:
子类调用父类的属性/方法
- super主要存在于子类方法中,用于指向子类对象中父类对象。
- 访问父类的属性
- 访问父类的函数
- 访问父类的构造函数
举个栗子:圆形和矩形都属于图形类
class Graph {
public double getPerimeter() {
return 0; // 因为不同的图形,计算方法不一样,所以这里先摆一个空壳
}
public double getArea() {
return 0;
}
}
class Circle extends Graph {
private double r;
public double getPerimeter() {
return Math.PI * 2 * r;
}
public double getArea() {
return Math.PI * r * r;
}
}
class Rectangle extends Graph {
private double width, height;
public double getPerimeter() {
return 2 * (width + height);
}
public double getArea() {
return width * height;
}
}
这样可以很明确的看出来这三个类的关系。
Override重写(覆盖、覆写):
在继承中,子类可以定义和父类相同的名称且参数列表一致的方法,将这种方法称之为方法的重写。
1:前提:必须要有继承关系
2:特点
- 当子类重写了父类的方法,那么子类的对象如果调用该方法,一定调用的是重写过后的方法。可以通过super进行父类的重写方法的调用。
- 继承可以使得子类可以增强/改写父类的方法
3:细节
3.1: 方法名必须相同
3.2: 参数列表必须相同
3.3: 子类重写父类的方法的时候,方法的访问权限必须大于等于父类的方法的访问权限,否则编译报错
3.4:子类重写父类的方法的时候,返回值类型必须是父类方法的返回值类型或该返回值类型的子类,不能返回比父类更大的数据类型。
4:子类对象查找属性或方法时的顺序:
原则:就近原则。
如果子类的对象调用方法,默认先使用this进行查找。
如果当前对象没有找到属性或方法,找当前对象中维护的super关键字指向的对象。
如果还没有找到,则编译报错,找到则直接调用。
在上面的例子中,圆形和矩形的计算周长和面积的方法都各不相同,所以都需要重写Graph类。
Override与Overload的区别
1:重载(overload):
- 1:前提:所有的重载方法必须在同一个类中
- 2:特点:方法名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)
- 3:三个不同:参数的个数不同、顺序不同、类型不同
2:重写(override):
- 1:前提:继承
- 2:特点:方法名必须相同、参数列表必须相同,子类的返回值类型要等于或者小于父类的返回值(继承与多态的思想,多态要到第10节再叨叨)
final关键字放在类上,则不允许被继承。一般两种情况要用final:
1. 为了防止代码功能被重写
2. 该类没有必要进行扩展
说了这么多,最后来一个综合性的例子吧!
- 定义动物类,会吃饭、睡觉、叫
- 定义猫,继承动物类,重写吃饭、叫
- 定义狗,继承动物类,重写睡觉、叫
class Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + "米西米西。。。");
}
public void sleep() {
System.out.println(name + "呼呼大睡。。。");
}
public void say() {
System.out.println(name + "发出叫声。。。");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("阿喵" + super.getName() + "大吃一顿。。。"); // 注意这里不能直接写name,关于该内容放到第12节说明
}
@Override
public void say() {
System.out.println("阿喵" + this.getName() + "喵喵的叫。。。");
}
}
class Dog extends Animal {
@Override
public void sleep() {
System.out.println("阿汪" + super.getName() + "睡个跟猪一样。。。");
}
@Override
public void say() {
System.out.println("阿汪" + this.getName() + "汪汪的叫。。。");
}
}





