• 抽象类和抽象方法


    1、设计理念

      父类要体现所有子类的共同特征,在设计某些方法(行为特征或功能)时,我们发现父类中无法给出合理的具体实现,而应该交由子类来实现,那么这样的方法就应该设计为抽象方法,而包含抽象方法的类就必须为抽象类。

      从另一个角度说,当父类表现为更通用的概念类,以至于创建它的实例对象没有实际意义,那么这样的父类就算没有抽象方法,也应该设计为抽象类。

      在Java中使用关键字abstract表示抽象。

    2、抽象方法

      所谓抽象方法,就是指没有方法体实现代码的方法,它仅具有一个方法签名。语法格式如下:

    [访问权限修饰符] abstract 返回值类型 方法名(参数列表) [throws 异常列表];
    
    • 1

      本地方法可以用private、static、final修饰,但是抽象方法不允许使用这些修饰符,否则子类将无法重写并实现抽象方法。

      另外,只允许在抽象类和接口中声明抽象方法,否则将发生编译错误。

    3、抽象类

      Java规定如果一个类中包含抽象方法,则该类必须设计为抽象类。当然,也并非所有的抽象类都包含抽象方法,当某个父类表现为更通用的概念类,以至于创建它的实例对象没有实际意义时,那么这样的父类就算没有抽象方法,也应该设计为抽象类。

      抽象类语法格式如下:

    [权限修饰符] abstract class 类名{
    
    }
    
    • 1
    • 2
    • 3

      抽象类也是类,所有类的成员在抽象类中都可以声明。

      为什么抽象方法所在的类必须声明为抽象类呢?

      如果不声明为抽象类,则此类就可以实例化,但是得到的对象对抽象方法的调用是无意义的,因为没有任何方法体。

    3.1 抽象类与普通类的区别

    • 抽象类不能直接实例化,即不能直接创建抽象类的对象。这是因为抽象类中可能包含抽象方法,而抽象方法没有方法体可以执行。虽然不能直接创建抽象类的对象,但是子类在创建对象时,一定会调用父类的构造器。或者可以说,任何Java中的类内部都一定有构造器。
    • 抽象类不能使用final修饰,因为抽象类是必须被子类继承的,否则它就失去了存在的意义,这与final正好矛盾。
    • 子类继承抽象类后,如果子类不再是抽象类,那么子类必须重写抽象类的所有抽象方法,否则编译报错。

    3.2 抽象类案例

      案例需求:声明一个父类Graphic,它表示图形,包含如下两个抽象方法:

    • 用于计算图形的面积:public abstract double area()
    • 用于返回图形的详细信息:public abstract String detail()

      再声明一个它的子类,一个是矩形(Rectangle),另一个是圆形(Circle),分别实现上面的抽象方法。在测试类的main方法中,创建一个Graphic类型的数组,里面存储了几个矩形和圆形的对象,并且按照它们的面积从小到大排序后,遍历输出每个图形的信息。

      父类Graphic代码:

    public abstract class Graphic {
        public abstract double area();
        public abstract  String detail();
    }
    
    • 1
    • 2
    • 3
    • 4

      子类Rectangle:

    public class Rectangle extends Graphic {
        private double length;
        private double width;
    
        public Rectangle(double length,double width){
            this.length=length;
            this.width=width;
        }
    
        @Override
        public double area() {
            return length*width;
        }
    
        @Override
        public String detail() {
            return "长方形的长:"+length+",宽:"+width+",面积是:"+area();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

      子类Circle代码:

    public class Circle extends Graphic {
        private double radius;
    
        public Circle(double radius){
            this.radius=radius;
        }
    
        @Override
        public double area() {
            return Math.PI*radius*radius;
        }
    
        @Override
        public String detail() {
            return "圆的半径是:"+radius+",面积是:"+area();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

      测试类代码:

    public class GraphicTest {
        public static void main(String[] args) {
            Graphic[] arr=new Graphic[4];
            arr[0]=new Rectangle(2,4);
            arr[1]=new Rectangle(1,2);
            arr[2]=new Circle(1.5);
            arr[3]=new Circle(2.0);
    
            //使用冒泡排序方法进行排序
            for(int i=1;i<arr.length;i++){
                for(int j=0;j<arr.length-i;j++){
                    if(arr[j].area()>arr[j+1].area()){
                        Graphic temp=arr[j];
                        arr[j]=arr[j+1];
                        arr[j+1]=temp;
                    }
                }
            }
    
            //遍历输出图形的信息
            for(int i=0;i<arr.length;i++){
                System.out.println(arr[i].detail());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    image-20220917153913695

      在上述代码中,子类Rectangle和子类Circle中必须重写父类Graphic的两个抽象方法,否则编译不通过。

      虽然不能直接创建抽象类Graphic的对象,但是可以创建Graphic[]对象数组,然后把它的元素存放在子类的实例对象中。

      当通过arr[i]调用area()和detail()方法时,编译器会去抽象类中找是否声明了这两个方法,如果没有声明,那么将会发生找不到该方法的编译错误,但是运行时是执行子类重写的area()和detail()方法,这又体现了多态性的使用。

  • 相关阅读:
    Elasticsearch:搜索架构
    C# 图解教程 第5版 —— 第3章 C# 编程概述
    Linux系统配置及服务管理-07-文件系统及RAID
    在centos上使用pyenv管理python及虚拟环境
    【机械仿真】基于matlab GUI直齿圆柱齿轮应力计算【含Matlab源码 2077期】
    解锁电力安全密码:迅软DSE助您保护机密无忧
    Vue中Slot的使用指南
    Git入门实战教程之创建版本库
    Postman进阶功能
    07 SpringMVC 拦截器
  • 原文地址:https://blog.csdn.net/qq_43753724/article/details/126906376