Java Final关键字,抽象类和抽象方法,抽象类实践-模板设计模式

final关键字:

  1. 用final关键字修饰的变量,它的值不允许更改,修饰的类不允许继承,修饰的方法不准许重写

  2. 使用规范,一般类用final修饰,里面的方法就不用修饰成final方法

  3. final修饰普通变量,有三个地方:

    1. 初始化时定义赋值

      private final double PI = 3.14;

    2. 普通代码块赋值

      public final int a;
          {
              a =10;
          }

    3. 构造器赋值

          private final double R;
          public Circle(double R) {
              this.R = R;
          }

  4. final修饰静态变量,有两个地方:

    1. 初始化定义赋值

    2. 静态代码块赋值

这个理解着记就好了,因为是final,修饰的变量不允许重新赋值,那么就只有一次赋值的机会,想想有哪些一次赋值的机会,初始化,构造器,代码块(相当于对构造器的补充),静态变量和非静态变量是分开的,就记住啦~

Tips:final和static搭配使用,在初始化时赋值,甚至连类都不用加载(节省点性能哦~),就能在外部调用它,如图

 这个还是挺有趣的一个小知识~,接下来事抽象方法和类:

抽象方法:

理解:父类确定子类的方法,但是方法具体执行什么内容不清楚,但是要求一定有子类的继承并重写该方法时,使用抽象方法和抽象类。抽象类的更多作用是设计,设计者设计好以后,让子类继承并实现它

使用方法:在类和要抽象的方法前加上abstract关键字:

abstract class Employee{
    public abstract void work();
}

使用细节:

  1. 抽象类不能被实例化

  2. 抽象类里可以没有抽象方法,但抽象方法所在类一定是抽象类

  3. abstract修饰类和方法,不修饰其他。

  4. 子类继承抽象类之后,必须重写其中所有抽象方法,除非它自己本身也是抽象类

    abstract class Employee{
        public abstract void work();
    }
    
    class Manager extends Employee{
        //继承父类方法
        @Override
        public void work() {
            System.out.printf("经理"+this.name+"工作中");
        }
    }
    
    abstract class Manager extends Employee{
        //定义为抽象类也不会报错,不过这种抽象继承抽象的写法非常少见
        
    }

  5. 抽象方法不能用private, final, static修饰,因为这些关键字逻辑上都是和重写相违背的。

理解:抽象方法本质是让子类重写方法体,private权限太高,子类继承后连访问都不可以,更别说重写了。final不必解释。关键的static,我的理解是,static设计出来就是给各个实例化的对象共享通用的,修饰方法时更多的是对静态成员进行操作,无法访问非静态成员。因为没有对实例化后的对象里的普通成员有相关操作,所以基本上用static修饰的方法不需要重写。而abstract修饰的抽象方法本意就是重写,两者冲突了。再者说,用static修饰的方法可以用 类名.方法名 直接调用,而 abstract修饰的方法没有方法体,两个在一起用的话,语法上的 类名.方法名 调用,岂不是调了个空方法体的方法?没有意义

学完了抽象类,但是觉得很难用上?接下来阿飞就和大家一起来看看它怎么用

抽象类实践-模板设计模式:

先来看看需求:

怎么写?先来最简单的方法,每个类,每个不一样的方法都写上一遍:

定义两个类,AA和BB,两个类里都有不同的任务,分别给每个任务计时:

public class AA{
    //计算 1+....+ 800000 的时间
    public void job() {
        //得到开始的时间
        long start = System.currentTimeMillis();
        long num = 0;
        for (long i = 1; i <= 800000; i++) {
            num += i;
        }
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("AA 第一个任务执行时间 " + (end - start));
    }

    //计算 1+....+ 1000000 的时间
    public void job2() {
        //得到开始的时间
        long start = System.currentTimeMillis();
        long num = 0;
        for (long i = 1; i <= 1000000; i++) {
            num += i;
        }
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("AA 第二个任务执行时间 " + (end - start));
    }
}
public class BB {
    //计算 1+....+ 1200000 的时间
    public void job() {
        //得到开始的时间
        long start = System.currentTimeMillis();
        long num = 0;
        for (long i = 1; i <= 1200000; i++) {
            num += i;
        }
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("BB 第一个任务执行时间 " + (end - start));
    }

    //计算 1+....+ 1400000 的时间
    public void job2() {
        //得到开始的时间
        long start = System.currentTimeMillis();
        long num = 0;
        for (long i = 1; i <= 1400000; i++) {
            num += i;
        }
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("BB 第二个任务执行时间 " + (end - start));
    }
}

 乍一看,每个方法都有重复的代码,太过冗余了。我们尝试着把它精简一下:

将每个类中相同逻辑的语句提取到一个calculateTime方法里,然后在那个方法里选择调用要计时的任务

public class AA{
    public void calculateTime() {
        //得到开始的时间
        long start = System.currentTimeMillis();

        //选择要计时的任务:如果还有更细致的操作可用一个方法将要执行的
        //所有操作封装起来,在这里调用那个方法
        job();  

        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("任务执行时间 " + (end - start));
    }

    //计算 1+....+ 800000 的时间
    public void job() {
        long num = 0;
        for (long i = 1; i <= 800000; i++) {
            num += i;
        }
    }

    //计算 1+....+ 1000000 的时间
    public void job2() {
        long num = 0;
        for (long i = 1; i <= 1000000; i++) {
            num += i;
        }
    }
}
public class BB {
    public void calculateTime() {
        //得到开始的时间
        long start = System.currentTimeMillis();
        job();  

        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("任务执行时间 " + (end - start));
    }
    
    //计算 1+....+ 1200000 的时间
    public void job() {
        long num = 0;
        for (long i = 1; i <= 1200000; i++) {
            num += i;
        }
    }

    //计算 1+....+ 1400000 的时间
    public void job2() {
        long num = 0;
        for (long i = 1; i <= 1400000; i++) {
            num += i;
        }
    }
}

这样的话代码就精简很多了,至少同一个类中的任务,不用每一个任务都加上计时的代码,不错吧?但是......

有没有发现,尽管同一个类中的不同任务不需要写相同的计时,但是不同的类,还是要重复写计时逻辑代码,它要是有一百个类,那岂不是要写上一百遍!?

这时就引出我们的抽象方法了,相同的逻辑,我们可以再提取一遍。这次把计时的逻辑提取到父类,让AA和BB去继承它,留出一个抽象的方法,让子类在里面自由发挥,就像这样:

abstract public class Template { //抽象类-模板设计模式

    public abstract void TotalJob();//抽象方法

    public void calculateTime() {//实现方法,调用TotalJob方法
        //得到开始的时间
        long start = System.currentTimeMillis();
        TotalJob();
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("任务执行时间 " + (end - start));
    }
}
public class AA extends Template {
    @Override
    public void TotalJob() {//AA这里计时两个任务
        job();
        job2();
    }
    //计算任务
    //1+....+ 800000
    public void job() { //实现Template的抽象方法job

        long num = 0;
        for (long i = 1; i <= 800000; i++) {
            num += i;
        }
    }
    //计算任务
    //1+....+ 1000000
    public void job2() {
        long num = 0;
        for (long i = 1; i <= 1000000; i++) {
            num += i;
        }
    }
}
public class BB extends Template {
    @Override
    public void TotalJob() {//BB这里计时一个任务
        job();
    }

    //计算 1+....+ 1200000 的时间
    public void job() {
        long num = 0;
        for (long i = 1; i <= 1200000; i++) {
            num += i;
        }
    }

    //计算 1+....+ 1400000 的时间
    public void job2() {
        long num = 0;
        for (long i = 1; i <= 1400000; i++) {
            num += i;
        }
    }
}

 现在,代码是不是看起来好多了?至少计时的逻辑只在父类出现过一次,然后全局通用。留出抽象的方法也可以在不同的子类里写不同的逻辑。这是基于抽象方法的一种模板设计模式,感觉吧还是挺重要的。参照B站韩老师的视频

~

~

~

我是阿飞,Java路上的萌新,希望和大家多多交流,期待和大家一起进步。完结撒花 ~ ~ ~ ~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值