学习内容:
- 一、继承概述
- 二、继承后的成员变量
- 三、继承后的成员方法
一、继承概述
1.概述
在Java中有非常之多的类,当多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。
其中,多个类可以称为子类、派生类,单独那一个类称为父类、超类(superclass)或者基类。
在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当作父类看待。
例如父类是员工,子类是讲师,那么“讲师就是一个员工”。关系:is-a
2.定义格式
定义父类的格式:(就是一个普通的类定义)
public class 父类名称 {
//...
}
定义子类的格式:
public class 子类名称 extends 父类名称 {
//...
}
下面我们举例简单说明:
定义一个父类,员工类,并且定义一个方法:
//定义一个父类:员工
public class Employee {
public void method() {
System.out.println("方法执行。");
}
}
再定义一个子类,讲师类:
//定义了一个员工的子类:讲师
public class Teacher extends Employee {
}
接下来我们定义一个测试类:
public class Demo01Extends {
public static void main(String[] args) {
//创建了一个子类对象
Teacher teacher = new Teacher();
//Teacher类当中虽然什么都没写,但是会继承来自父类的method()方法
teacher.method();
}
}
可以看到,我们创建了一个讲师类(子类)的对象,可以调用员工类(父类)的方法。这就体现了继承的思想。
二、继承后的成员变量
当类之间产生继承关系之后,子类便继承了父类的成员变量,对于不重名的成员变量,我们可以访问,不产生任何影响;但对于重名的成员变量,我们若想在子类当中访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量,类似于之前学过的 this 。
代码示例:
父类中的成员变量:
public class Fu {
//父类中的成员变量
int num = 100;
}
子类中访问:
public class Zi extends Fu {
// 子类中的成员变量
int num = 200;
public void show() {
//访问父类中的num
System.out.println("Fu num=" + super.num); // 100
//访问子类中的num
System.out.println("Zi num=" + this.num); // 200
}
}
在创建子类对象时,访问有两种方式
- 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找。
- 间接通过成员方法访问成员变量:看方法属于谁,就优先用谁,没有则向上找。
代码简单说明:
定义父类:
public class Fu {
int numFu = 10;
int num = 100;
public void methodFu() {
//使用的是本类当中的,不会向下找子类的
System.out.println(num);
}
}
定义子类:
public class Zi extends Fu{
int numZi = 20;
int num = 200;
public void methodZi() {
//因为本类当中有num,所以这里用的是本类的num
System.out.println(num);
}
}
访问方式测试:
public class Demo01ExtendsField {
public static void main(String[] args) {
Fu fu = new Fu(); // 创建父类对象
System.out.println(fu.numFu); // 只能使用父类的东西,没有任何子类内容
System.out.println("--------------------");
Zi zi = new Zi();
System.out.println(zi.numFu); // 10 不重名的成员变量,访问不产生任何影响
System.out.println(zi.numZi); // 20
System.out.println("--------------------");
//等号左边是谁,就优先用谁
System.out.println(zi.num); //优先子类,200
System.out.println("--------------------");
//这个方法是子类的,优先用子类的,如果没有再向上找
zi.methodZi(); // 200
//这个方法是父类当中定义的
zi.methodFu(); // 100
}
}
三、继承后的成员方法
在继承中,与成员变量一样,子类继承了父类的成员方法,如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
代码示例:
定义父类:
public class Fu {
public void method01() {
System.out.println("父类方法执行");
}
}
定义子类:
public class Zi {
public void method02() {
System.out.println("子类方法执行");
}
}
定义测试类:
public class ExtendsDemo04 {
public static void main(String[] args) {
Zi zi = new Zi();
//子类中没有method01,去父类中找到并执行
zi.method01();
//子类自己的方法,直接执行
zi.method02();
}
}
当如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,我们引入一个概念,叫做方法重写 (Override)。
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
一般的在父子类的继承关系当中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先用谁,如果没有则向上找。即:创建的是子类对象,则优先用子类方法。
下面用代码简单说明:
定义父类:
public class Fu {
public void methodFu() {
System.out.println("父类方法执行");
}
public void method() {
System.out.println("父类重名方法执行");
}
}
定义子类:
public class Zi extends Fu {
public void methodZi() {
System.out.println("子类方法执行");
}
public void method() {
System.out.println("子类重名方法执行");
}
}
定义测试类:
public class Demo01ExtendsMethod {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodFu(); // 父类方法执行
zi.methodZi(); // 子类方法执行
// 创建的是子类对象,所以优先用子类方法
zi.method(); // 子类重名方法执行
}
}
方法覆盖重写的注意事项:
- 必须保证父子类之间方法的名称相同,参数列表也相同。
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。
这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。 - 子类方法的返回值必须【小于等于】父类方法的返回值范围。
java.lang.Object类是所有类的公共最高父类(祖宗),java.lang.String就是Object的子类。 - 子类方法的权限必须【大于等于】父类方法的权限修饰符。
public > protected > (default) > private
注意:(default)不是关键字default,而是什么都不写,留空。