zoukankan      html  css  js  c++  java
  • Java 抽象类 抽象方法 使用说明

    知识点

    • 什么是抽象类
      抽象类与普通类主要两点不同:
      1、在类的修饰符后面多了一个abstract关键字
      2、抽象类是不允许通过new来实例化的
      由于抽象类不能通过new来实例化,所以基本上是在继承中当做父类使用。

    • 什么是抽象方法
      抽象方法的定义需要加上abstract关键字,不能有方法体,以封号结尾,比如:
      public abstract void getOtherSalary();
      抽象方法的具体实现,需要在子类中实现。注意:static、final的方法,不能被申明为抽象方法。

    • 抽象类与抽象方法
      抽象类不一定包含抽象方法,但如果一个类包含了抽象方法,那这个类一定是抽象类,否则编译不通过。

    • 什么时候用抽象方法
      抽象方法通常用于父类中。父类通常都是用于定义一些公共方法、公共属性等,但是实际项目可能会出现某些方法定义在父类中,父类却无法给出具体的实现,此时就是抽象方法出场的时候了。比如下文实例中,职员在公司中的收入都包含基本工资以及绩效奖金,基本工资大家都一样,但是绩效奖金就因岗位而异了,所以绩效奖金在职员类中只是个方法体,没有具体实现。

    • 抽象方法与设计模式
      抽象方法在设计模式中有比较多的体现,特别是用于 模板方法设计模式,详见下文实例

    实例

    1.抽象方法的使用

    需求描述:公司里的职员分为普通程序员和技术总监,所有职员的基本薪水都是10000元每个月,程序员的绩效奖金每个月3000元,技术总监的绩效奖金每个月20000元。

    了解了需求后,我们先定义一个职员类Employee,如下:

    /**
     * 定义职工类,每个职工的薪水都由基本薪资跟绩效奖金组成
     */
    public abstract class Employee {
    
        /**
         * 岗位名称
         */
        private String jobName;
    
        /**
         * 所有职工的每月基本薪资都一样
         * @return
         */
        public int getBaseSalary(){
            return 10000;
        }
    
        /**
         * 所有职工都有绩效奖金,但是普通程序员跟技术总监的不一样,
         * 所以这里无法给出具体实现,需要在子类中实现
         * @return
         */
        public abstract int getOtherSalary();
    
        public String getJobName() {
            return jobName;
        }
    
        public void setJobName(String jobName) {
            this.jobName = jobName;
        }
    }
    

    定义程序员类Coder,继承职员类,实现getOtherSalary() 方法,如下:

    /**
     * 程序员类,继承Employee类
     */
    public class Coder extends Employee{
    
        /**
         * 由于继承了Employee类,所以必须实现Employee类中的抽象方法getOtherSalary()
         * @return
         */
        @Override
        public int getOtherSalary() {
            return 3000;
        }
    }
    

    定义技术总监类Cto,继承职员类,实现getOtherSalary() 方法,如下:

    /**
     * 技术总监类,继承Employee类
     */
    public class Cto extends Employee{
    
        /**
         * 由于继承了Employee类,所以必须实现Employee类中的抽象方法getOtherSalary()
         * @return
         */
        @Override
        public int getOtherSalary() {
            return 20000;
        }
    }
    

    最后打印程序员与技术总监每个月的薪水:

    public class AbstractMain {
    
        public static void main(String[] args){
            Coder coder = new Coder();
            coder.setJobName("程序员");
            System.out.println(coder.getJobName() + "每个月薪资为:");
            System.out.println("基本薪资:" + coder.getBaseSalary() + "元");
            System.out.println("绩效奖金:" + coder.getOtherSalary() + "元");
    
            Cto cto = new Cto();
            cto.setJobName("技术总监");
            System.out.println(cto.getJobName() + "每个月薪资为:");
            System.out.println("基本薪资:" + cto.getBaseSalary() + "元");
            System.out.println("绩效奖金:" + cto.getOtherSalary() + "元");
        }
    }
    

    执行以上程序后,输出:

    程序员每个月薪资为:
    基本薪资:10000元
    绩效奖金:3000元
    
    技术总监每个月薪资为:
    基本薪资:10000元
    绩效奖金:20000元
    

    2.抽象方法与模板方法设计模式

    在完成了以上需求后,此时又提出新需求,按照以下格式打印每个月的工资条,并且打印的顺序必须按以下格式打印出来:

    XXX每个月薪资为:
    基本薪资:XXX元
    绩效奖金:XXX元
    该月总工资为:XXX元
    

    按照第一个例子的实现方式无法满足这个需求,第一个例子的打印顺序是由调用者决定的,无法统一控制。此时就是模板方法设计模式登场的时候了。基于第一个例子,改造一下职员类Employee,增加打印工资条的方法public final void printSalary()如下:

    /**
     * 定义职工类,每个职工的薪水都由基本薪资跟绩效奖金组成
     */
    public abstract class Employee {
    
        /**
         * 岗位名称
         */
        private String jobName;
    
        /**
         * 所有职工的每月基本薪资都一样
         * @return
         */
        public int getBaseSalary(){
            return 10000;
        }
    
        /**
         * 所有职工都有绩效奖金,但是普通程序员跟技术总监的不一样,
         * 所以这里无法给出具体实现,需要在子类中实现
         * @return
         */
        public abstract int getOtherSalary();
    
        /**
         * 获取每个月工资总额
         * @return
         */
        public int getTotalSalary(){
    
            return this.getBaseSalary() + this.getOtherSalary();
        }
    
        /**
         * 定义执行顺序模板,模板中有些方法(抽象方法)是要在子类中实现
         * 打印工资条,定义为final类,禁止被子类重写
         */
        public final void printSalary(){
    
            System.out.println(this.jobName + "每个月薪资为:");
            System.out.println("基本薪资:" + this.getBaseSalary() + "元");
            System.out.println("绩效奖金:" + this.getOtherSalary() + "元");
            System.out.println("该月总工资为:" + getTotalSalary() + "元");
        }
    
        public String getJobName() {
            return jobName;
        }
    
        public void setJobName(String jobName) {
            this.jobName = jobName;
        }
    }
    

    打印每个月工资条:

    public class AbstractMain {
    
        public static void main(String[] args){
            Coder coder = new Coder();
            coder.setJobName("程序员");
            coder.printSalary();
    
            Cto cto = new Cto();
            cto.setJobName("技术总监");
            cto.printSalary();
        }
    }
    

    以上执行结果为:

    程序员每个月薪资为:
    基本薪资:10000元
    绩效奖金:3000元
    该月总工资为:13000元
    
    技术总监每个月薪资为:
    基本薪资:10000元
    绩效奖金:20000元
    该月总工资为:30000元
    

    源码获取

    以上示例都可以通过我的GitHub获取完整的代码,点击获取

  • 相关阅读:
    学会Git玩转Github笔记(一)——Github基本概念 & 仓库管理
    Github 入门基本操作
    Struts2拦截器浅析
    SSH(Struts2+Spring4+Hibernate4)框架教程之配置篇
    Spring 体系结构
    Ubuntu启动sshd服务
    jquery ajax/post 请求 案例
    Elasticsearch 配置
    Jenkins安装与配置
    解决Ubuntu环境变量错误导致无法正常登录  (command 'xxx' is available in bin ls)
  • 原文地址:https://www.cnblogs.com/mingsay/p/12460584.html
Copyright © 2011-2022 走看看