Java学习 -- 抽象类和抽象方法

2023-04-11 08:08:16

引言

在之前学习过的继承和多态中,我们对于类的继承关系有了深刻的理解。在Java中我们将类的继承关系抽象为一个自上而下的层级结构,上面是父类下面是子类,显然层级越高的父类所代表的范围越广泛,因此也更加的抽象。比如Object是Java中的公共最高父类,那么Object到底是个啥?好像它啥都是,又好像啥也不是。所以说Object这个类通用性就非常广,同时也非常抽象(注意:Object并不是抽象类,这里只是做了一个比喻)

假设我们有一个类,就比如说是图形类把,它可以用来表示所有的图形。图形有什么属性和功能呢?首先图形肯定是有面积的,所以图形也应该具备计算面积的方法。可是这个计算面积的方法应该怎么实现呢?图形的子类可以有很多,比如说正方形、三角形、圆形… 每一个具体的图形它们的面积计算公式是不同的,所以对于图形这个父类中计算面积的方法就很难去定义它的方法体。

// 图形类
public class Shape {

    public double calculateArea() {
      // ...怎么写?  
        return // ?
    }
}

// 正方形类
class Square extends Shape {
    double sideLength;

    @Override
    public double calculateArea() {
        return Math.pow(sideLength, 2);
    }

}

// 三角形类
class Triangle extends Shape {
    double base;
    double height;

    @Override
    public double calculateArea() {
        return base * height / 2;
    }
}
// 圆形类
class Circle extends Shape {
    double radius;

    @Override
    public double calculateArea() {
        return Math.PI * Math.pow(radius, 2);
    }
}

既然这么难去定义,能不能不定义方法体,直接让子类覆盖重写父类中的这个方法呢?。当然可以,程序员是不会和自己过不去的,既然存在一些类它们当中的一些方法是很难去定义的,索性咱就改改代码不去定义得了,废这个脑细胞都够耽误我摸一盆🐟了。

抽象方法

这个不定义方法体的方法,就是抽象方法。而定义抽象方法使用 abstract 关键字,被abstract修饰的方法就是抽象方法

定义格式如下:

修饰符 abstract 返回值类型 方法名(参数列表); // 不写{}, 没有方法体。

在这里插入图片描述

现在我们尝试使用abstract关键字来修饰父类中的计算面积方法。

// 图形类
public class Shape {
    public abstract double calculateArea();
}

当把这个方法定义为抽象方法后,编译器直接报错,提示我们在非抽象类中定义了抽象方法。
在这里插入图片描述
这是为什么呢?这里我们需要牢记一个规则:如果一个类包含抽象方法,那么该类必须是抽象类

抽象类

抽象类是由abstract关键字所修饰的类,抽象类主要用于被子类继承被覆盖重写其中的抽象方法,子类重写抽象父类的抽象方法的过程也被称作实现方法,对于子类实现的方法不能再加上abstract关键字。

定义格式如下:

修饰符 abstract class 类名称 {
   // ...
}

现在我们将图形类改为抽象类,再看看程序能否正常允许。

// 图形类
public abstract class Shape {
    public abstract double calculateArea();
}

在这里插入图片描述
可以看到,子类实现了抽象父类的方法后,程序可以正常运行。不过关于抽象类还有许多需要注意的事项,下面一起来看一看。

抽象类的注意事项

  1. 抽象类不能被实例化。

    抽象类的主要作用就是为了被子类继承并实现的其中的抽象方法,抽象类中大部分定义的都是没有方法体的抽象方法,所以对抽象类进行实例化没有意义。

在这里插入图片描述

  1. 抽象类作为一个类,其内部是有构造器的,不过抽象类的构造器并不是为了本类实例化,而是为了子类在实例化中加载父类结构而存在的。
    在这里插入图片描述在这里插入图片描述

  2. 抽象类中可以定义普通方法和属性。

在这里插入图片描述

  1. 抽象类中,不一定包含抽象方法,但是包含抽象方法的一定是抽象类。

    未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计(比如一些工具类,其中定义了静态方法提供使用,无序对该类实例化)。

在这里插入图片描述

  1. 抽象类的子类,要么实现抽象父类的所有抽象方法,要么该子类本身也是一个抽象类
    在这里插入图片描述

  2. 一个抽象类A可以被另一个抽象类B继承,但是如果有另外的普通类C继承了抽象类B,那么普通类C所继承的所有抽象方法被必须被重写。

在这里插入图片描述

  1. final和abstract不能共存

final修饰类时表示该类不能被继承,final修饰方法时表示该方法不能被重写。

而abstract修饰的类需要被子类继承,abstract修饰的方法必须要被子类重写。

两个关键字功能相互矛盾,所以不可以共存!

注意点:final类中的所有成员方法都会被隐式地指定为final方法。

在这里插入图片描述
在这里插入图片描述
8. private不能用来修饰抽象方法

在继承关系中我们学习过对于父类的private的方法,子类是不可见的,也就谈不上覆盖重写。

而另一个的原因是private所修饰的方法会被隐式的指定为final方法,这也说明了private所修饰的方法为什么不能被覆盖重写。

当方法被final或者private修饰时,该方法就从动态绑定转变为静态绑定,那么该方法也就失去了重写的意义。

在这里插入图片描述

  1. 抽象类是适用于多态性的。

    抽象类满足多态的三个必要条件:

    1. 继承,抽象类的意义就是为了被继承。
    2. 重写,抽象类的抽象方法必须被重写。
    3. 向上转型,抽象类虽然不能被实例化,但是允许抽象类的引用指向子类对象。

    可以看到,抽象类完美的契合了多态的三个必要条件。

  • 作者:庸人冲
  • 原文链接:https://blog.csdn.net/weixin_48084293/article/details/120410914
    更新时间:2023-04-11 08:08:16