0
点赞
收藏
分享

微信扫一扫

第八天:继承、super与this、抽象类

Sophia的玲珑阁 2021-09-19 阅读 77
JAVA基础

一.继承

(一)概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。其中,多个类可以称为,单独那一个类称为、超类(superclass)或者基类。继承描述的是事物之间的所属关系,这种关系是:的关系。

1.定义

继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

2.优点
  • 提高代码的复用性。
  • 类与类之间产生了关系,是多态的前提。
3.继承关系当中的特点:
  • 子类可以拥有父类的内容
  • 子类还可以拥有自己专有的内容。

(二)继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {
  ...
}
class 子类 extends 父类 {
  ...
}

代码:

/*
 * 定义员工类Employee,做为父类
 */
class Employee {
    String name; // 定义name属性

    // 定义员工的工作方法
    public void work() {
        System.out.println("尽心尽力地工作");
    }
}

/*
 * 定义讲师类Teacher 继承 员工类Employee
 */
class Teacher extends Employee {
    // 定义一个打印name的方法
    public void printName() {
        System.out.println("name=" + name);
    }
}

/*
 * 定义测试类
 */
public class ExtendsTest1 {
    public static void main(String[] args) {
        // 创建一个讲师类对象
        Teacher t = new Teacher();
        // 为该员工类的name属性进行赋值
        t.name = "小明";
        // 调用该员工的printName()方法
        t.printName(); // name = 小明
        // 调用Teacher类继承来的work()方法
        t.work(); // 尽心尽力地工作
    }
}

运行结果:

(三)Java中继承的特点

  1. Java只支持单继承,不支持多继承。
  2. Java支持多级继承(继承体系)。
  3. 一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类。

(四)继承后的特性

1.父类与子类成员变量重名

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式。
访问规则:

  • 直接通过子类对象访问成员变量:
    等号左边是谁,就优先用谁,没有则向上找。
  • 间接通过成员方法访问成员变量:
    该方法属于谁,就优先用谁,没有则向上找。

代码:

class Fu {
    // Fu中的成员变量。
    int num = 100;

    public void methodFu() {
        // 访问父类中的num
        System.out.println("methodFu: " + num);
    }
}

class Zi extends Fu {
    // Zi中的成员变量
    int num = 200;

    public void methodZi() {
        // 访问子类中的num
        System.out.println("methodZi: " + num);
    }
}

public class ExtendTest2 {
    public static void main(String[] args) {
        // 创建父类对象
        Fu fu = new Fu();
        // 创建子类对象
        Zi zi = new Zi();

        // 等号左边是谁,就优先用谁
        System.out.println("zi.num: "+zi.num); // 优先子类,200
        System.out.println("fu.num: "+fu.num); // 100

        // 该方法属于谁,就优先用谁
        zi.methodZi(); // 200
        zi.methodFu(); // 100
    }
}

运行结果:

2.子类中的三种变量重名

代码:

class Fu {
    // Fu中的成员变量。
    int num = 10;

}

class Zi extends Fu {
    // Zi中的成员变量
    int num = 20;

    public void method() {
        int num = 30;
        // 访问局部变量num
        System.out.println("子类当中的局部变量: " + num);

        System.out.println("子类当中的成员变量 " + this.num);

        System.out.println("父类当中的成员变量: " + super.num);
    }
}

public class ExtendTest3 {
    public static void main(String[] args) {
        // 创建子类对象
        Zi zi = new Zi();
        zi.method();
    }
}

运行结果:

3.成员方法重名—重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
访问规则:
看new的是谁,就优先用谁,没有则向上找。

  • 方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。

代码:

class Fu {
    public void show() {
        System.out.println("父类show方法执行");
    }
}

class Zi extends Fu {
    //子类重写了父类的show方法
    @Override
    public void show() {
        System.out.println("子类show方法执行");
    }
}

public class OverrideTest1 {
    public static void main(String[] args) {
        Zi z = new Zi();
        // new的是Zi,子类中有show方法,只执行重写后的show方法
        z.show();
    }
}

运行结果:

重写的应用:
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。



代码:

// 手机类
class Phone {
    public void sendMessage() {
        System.out.println("发短信");
    }

    public void call() {
        System.out.println("打电话");
    }

    public void showNum() {
        System.out.println("来电显示号码");
    }
}

// 智能手机类
class NewPhone extends Phone {
    // 重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能
    @Override
    public void showNum() {
        //调用父类已经存在的功能使用super
        super.showNum();

        //增加自己特有显示姓名和图片功能
        System.out.println("显示来电姓名");
        System.out.println("显示头像");
    }
}

public class ExtendsPhone {
    public static void main(String[] args) {
        // 创建子类对象
        NewPhone np = new NewPhone();
        // 调用父类继承而来的方法
        np.call();
        // 调用子类重写的方法
        np.showNum();
    }
}

运行结果:

4.继承后的特点—构造方法

继承关系中,父子类构造方法的访问特点:

  • 子类构造方法当中有一个默认隐含的super()调用,所以一定是先调用的父类构造,后执行的子类构造。
  • 子类构造可以通过super关键字来调用父类重载构造。
  • super的父类构造调用, 必须是子类构造方法的第一个语句。 不能一个子类构造调用多次super构造。

代码:

class Fu {
    Fu() {
        System.out.println("父类无参构造方法!");
    }

    Fu(int num) {
        System.out.println("父类有参构造方法!" + "num值为: " + num);
    }
}

class Zi extends Fu {
    Zi() {
        // super(); // 调用父类无参构造方法(默认赠送,可以不写)
        System.out.println("子类无参构造方法!");
    }

    Zi(int num) {
        super(10); // 调用父类有参构造方法
        System.out.println("子类有参构造方法!" + "num值为: " + num);
    }
}

public class ExtendsConstructor {
    public static void main(String[] args) {
        Zi one = new Zi();
        Zi two = new Zi(20);
    }
}

运行结果:

二.super与this关键字

(一)super和this的含义

  • super :代表父类的存储空间标识(可以理解为父亲的引用)。
  • this :代表当前对象的引用(谁调用就代表谁)。

(二)super关键字的三种用法:

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。

代码:

class Fu {
    int num = 10;

    Fu() {
        System.out.println("父类构造方法");
    }

    public void method() {
        System.out.println("父类method方法!");
    }
}

class Zi extends Fu {
    int num = 20;

    Zi() {
        super(); // 访问父类的构造方法
        System.out.println("子类构造方法");
    }

    @Override
    public void method() {
        System.out.println("父类num值: " + super.num); // 访问父类的成员变量num
        System.out.println("子类num值: " + num);
        super.method(); // 访问父类的成员方法method
        System.out.println("子类method方法!");
    }
}

public class SuperExtends {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}

运行结果:

(三)super关键字的三种用法

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另一个成员方法。
  3. 在本类的构造方法中,访问本类的另一个构造方法。

代码:

class Fu {
    int num = 10;
}

class Zi extends Fu {
    int num = 20;

    public Zi() {
        this(123); // 访问本类的另一个构造方法
        System.out.println("无参构造方法执行!");
    }

    public Zi(int n) {
        System.out.println("有参构造方法执行!");
    }

    public void showNum() {
        int num = 30;
        System.out.println("局部变量num值:" + num);
        System.out.println("本类当中成员变量num值:" + this.num); // 访问本类的成员变量
    }

    public void MethodA() {
        System.out.println("成员方法MethodA执行!");
    }

    public void MethodB() {
        this.MethodA(); // 访问本类的另一个成员方法,this可以省略
        System.out.println("成员方法MethodB执行!");
    }
}

public class ThisExtends {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.showNum();
        zi.MethodB();
    }
}

运行结果:

(四)内存图

三.抽象类

(一)概述

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有还有意义,而则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,抽象方法的类就是抽象类。

(二)定义

  • 抽象方法:没有方法体的方法。
  • 抽象类:包含抽象方法的类。

(三)abstract使用格式

1.抽象方法

使用abstract关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

  • 定义格式:修饰符 abstract 返回值类型 方法名 (参数列表);
  • 代码举例:public abstract void run();
2.抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。

  • 定义格式:abstract class 类名字 {}
  • 代码举例:
public abstract class Animal {
  public abstract void run();
}

(四)如何使用抽象类和抽象方法:

  1. 不能直接创建new抽象类对象。
  2. 必须用一个子类来继承抽象父类。
    重写():子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
  3. 子类必须重写抽象父类当中所有的抽象方法。
  4. 创建子类对象进行使用

代码:

abstract class Animal {
    public abstract void eat();
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}

public class AbstractTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }
}

运行结果:

(五)注意事项

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
  1. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
  1. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  1. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
举报

相关推荐

0 条评论