当前位置: 首页 > news >正文

8 面向对象编程 8.5. final 关键字 8.6 抽象类 8.7 抽象类最佳实践-模板设计模式

8 面向对象编程

8.5. final 关键字

8.5.1 基本介绍

final 中文意思:最后的, 最终的.
final 可以修饰类、属性、方法和局部变量.
在某些情况下,程序员可能有以下需求, 就会使用到final:

    1. 当不希望类被继承时,可以用final修饰.【案例演示】
    1. 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。【案例演示:访问修饰符 final 返回类型 方法名 】
    1. 当不希望类的的某个属性的值被修改,可以用final修饰.【案例演示: public final double TAX_RATE=0.08】
    1. 当不希望某个局部变量被修改, 可以使用final修饰【案例演示: final double TAX_RATE=0.08 】
public class Final01 {public static void main(String[] args) {E e = new E();// e.TAX_RATE = 0.09; // 编译错误,不能修改final属性的值}
}// 如果我们要求A类不能被其他类继承,可以使用final修饰A类
final class A { }// class B extends A {} // 编译错误,不能继承final类class C {// 如果我们要求hi不能被子类重写,可以使用final修饰hi方法public final void hi() {}
}class D extends C {// 编译错误,不能重写final方法/*@Overridepublic void hi() {System.out.println("重写了 C 类的 hi 方法..");}*/
}// 当不希望类的某个属性的值被修改,可以用final修饰
class E {public final double TAX_RATE = 0.08; // 常量
}// 当不希望某个局部变量被修改,可以使用final修饰
class F {public void cry() {// 这时,NUM也称为局部常量final double NUM = 0.01;// NUM = 0.9; // 编译错误,不能修改final局部变量的值System.out.println("NUM=" + NUM);}
}

8.5.2 final 使用注意事项和细节讨论

    1. final修饰的属性又叫常量,一般用XX_XX_XX来命名
    1. final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】:
      ① 定义时:如public final double TAX_RATE=0.08;
      ② 在构造器中
      ③ 在代码块中。
    1. 如果final修饰的属性是静态的,则初始化的位置只能是
      ① 定义时 ② 在静态代码块 不能在构造器中赋值。
    1. final类不能继承,但是可以实例化对象。[A2类]
    1. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。[A3类]
    public class FinalDetail01 {public static void main(String[] args) {CC cc = new CC();  // 修正了变量名的语法错误new EE().cal();}
    }class AA {/*1. 定义时:如 public final double TAX_RATE=0.08;2. 在构造器中3. 在代码块中*/public final double TAX_RATE = 0.08;  // 1.定义时赋值public final double TAX_RATE2;public final double TAX_RATE3;public AA() {  // 构造器中赋值TAX_RATE2 = 1.1;}{  // 在代码块中赋值TAX_RATE3 = 8.8;}
    }class BB {/*如果final修饰的属性是静态的,则初始化的位置只能是1. 定义时 2. 在静态代码块 不能在构造器中赋值。*/public static final double TAX_RATE = 99.9;  // 静态常量定义时赋值public static final double TAX_RATE2;static {  // 静态代码块中为静态常量赋值TAX_RATE2 = 3.3;}
    }// final类不能继承,但是可以实例化对象
    final class CC { }// 非final类可以被继承
    class DD {// final方法不能被重写,但可以被继承public final void cal() {System.out.println("cal()方法");}
    }// 继承DD类,可以使用父类的final方法
    class EE extends DD { }
    1. 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。
    1. final不能修饰构造方法(即构造器)
    1. final 和 static 往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理。
    class Demo{public static final int i=16; //static{System.out.println("~666");}
    }
    此处若调用Demo.i 不会导致类加载故~666不会输出
    
    1. 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
    public class FinalDetail02 {public static void main(String[] args) {System.out.println(BBB.num);// 包装类和String是final类,不能被继承// 例如: class MyString extends String {} // 编译错误// 例如: class MyInteger extends Integer {} // 编译错误}
    }// final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理
    class BBB {public final static int num = 10000;static {System.out.println("BBB静态代码块被执行");}
    }final class AAA {// 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法// public final void cry() {} // 这里注释掉了多余的final修饰
    }

8.6 抽象类

8.6.1 先看一个问题 Abstract01.java

public class Abstract01 {public static void main(String[] args) {// 抽象类不能被实例化// Animal animal = new Animal("动物"); // 编译错误}
}//思考:这里eat 这里你实现了,其实没有什么意义
//即: 父类方法不确定性的问题
//===> 考虑将该方法设计为抽象(abstract)方法
//===> 所谓抽象方法就是没有实现的方法
//===> 所谓没有实现就是指,没有方法体
//===> 当一个类中存在抽象方法时,需要将该类声明为abstract类
//===> 一般来说,抽象类会被继承,有其子类来实现抽象方法
abstract class Animal {private String name;public Animal(String name) {this.name = name;}// 原有的具体方法实现(已注释,因为与抽象方法冲突)/*public void eat() {System.out.println("这是一个动物,但是不知道吃什么..");}*/// 抽象方法:没有方法体,需要子类实现public abstract void eat();
}

8.6.2 解决之道-抽象类快速入门

当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法, 这个方法就是抽象方法,用abstract 来修饰该类就是抽象类。
我们看看如何把Animal做成抽象类, 并让子类Cat类实现。
abstract class Animal{
String name;
int age;
abstract public void cry();
}

8.6.3 抽象类的介绍

    1. 用abstract 关键字来修饰一个类时,这个类就叫抽象类
      访问修饰符 abstract 类名{
      }
    1. 用abstract 关键字来修饰一个方法时,这个方法就是抽象方法
      访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
    1. 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()
    1. 抽象类,是考官比较爱问的知识点, 在框架和设计模式使用较多

8.6.4 抽象类使用的注意事项和细节讨论 AbstractDetail01.java

    1. 抽象类不能被实例化 [举例]
    1. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法 [举例]
    1. 一旦类包含了abstract方法,则这个类必须声明为abstract [说明]
    1. abstract 只能修饰类和方法,不能修饰属性和其它的。[说明]
public class AbstractDetail01 {public static void main(String[] args) {// 抽象类不能被实例化// new A(); // 编译错误}
}// 抽象类不一定要包含abstract方法,也可以有实现的方法
abstract class A {public void hi() {System.out.println("hi");}
}// 一旦类包含了abstract方法,则这个类必须声明为abstract
abstract class B {public abstract void hi();
}// abstract只能修饰类和方法,不能修饰属性和其它元素
class C {// public abstract int n1 = 1; // 编译错误,abstract不能修饰属性
}

8.6.5 抽象类使用的注意事项和细节讨论 AbstractDetail02.java

    1. 抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法、构造器、静态属性等等 [举例]
    1. 抽象方法不能有主体,即不能实现.如图所示
      abstract void aaa(){}; (此处大括号上有红色叉号示意错误 )
    1. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。[举例 A类,B类,C类]
    1. 抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的。
    public class AbstractDetail02 {public static void main(String[] args) {System.out.println("hello");}
    }// 抽象方法不能使用private、final和static来修饰,因为这些关键字与重写相违背
    abstract class H {// 以下都是错误的抽象方法声明方式// private abstract void hi();   // 错误:private与重写冲突// final abstract void hi();    // 错误:final与重写冲突// static abstract void hi();   // 错误:static与重写冲突public abstract void hi(); // 正确的抽象方法声明
    }// 如果一个类继承了抽象类,则它必须实现所有抽象方法,除非自身也声明为abstract
    abstract class E {public abstract void hi();
    }// F类继承了抽象类E,但没有实现抽象方法,因此自身必须声明为abstract
    abstract class F extends E {
    }// G类继承了抽象类E,必须实现所有抽象方法
    class G extends E {@Overridepublic void hi() { // 实现父类的抽象方法,必须有方法体System.out.println("G类实现了E类的hi()方法");}
    }// 抽象类的本质还是类,所以可以有类的各种成员
    abstract class D {// 非静态属性public int n1 = 10;// 静态属性public static String name = "韩顺平教育";// 非抽象方法public void hi() {System.out.println("hi");}// 抽象方法public abstract void hello();// 静态方法public static void ok() {System.out.println("ok");}
    }

8.7 抽象类最佳实践-模板设计模式

8..7.1 基本介绍

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

8.7.2 模板设计模式能解决的问题

    1. 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    1. 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。

8.7.3 最佳实践

需求

    1. 有多个类,完成不同的任务job
    1. 要求统计得到各自完成任务的时间
    1. 精确性实现 TestTemplate.java
    1. 矫情的自然浓缩
      感情的自然浓缩
  1. 先用最容易想到的方法-》代码实现
  2. 分析问题,提出使用模板设计模式
package com.ming.abstract_;// 抽象类-模板设计模式
public abstract class Template {// 抽象方法,由子类实现具体任务public abstract void job();// 模板方法,计算任务执行时间public void calculateTime() {// 记录开始时间long start = System.currentTimeMillis();job(); // 动态绑定,调用子类的实现// 记录结束时间long end = System.currentTimeMillis();System.out.println("任务执行时间: " + (end - start) + " 毫秒");}
}
package com.ming.abstract_;public class AA extends Template {// 实现Template的抽象方法job,完成累加任务@Overridepublic void job() {long num = 0;for (long i = 1; i <= 800000; i++) {num += i;}}
}
package com.ming.abstract_;public class BB extends Template {// 重写Template的job方法,完成累乘任务@Overridepublic void job() {long num = 1;for (long i = 1; i <= 80000; i++) {num *= i;}}
}
package com.ming.abstract_;public class TestTemplate {public static void main(String[] args) {// 创建AA对象并计算其任务执行时间AA aa = new AA();aa.calculateTime(); // 利用多态调用模板方法// 创建BB对象并计算其任务执行时间BB bb = new BB();bb.calculateTime();}
}
http://www.sczhlp.com/news/9989/

相关文章:

  • [Atlas200I A2] 安装torch-npu
  • 题解:[Vani有约会] 雨天的尾巴 /【模板】线段树合并
  • 8.11随笔
  • 蒸馏大型语言模型并超越其性能
  • webrtc自定义端口和host
  • 【20250805省选训练】T3-简单树题
  • 让CPU省电的方法
  • IFEO劫持
  • GAS_Aura-Highlight Enemies
  • linux中node环境管理
  • 训练专有大模型的核心路径
  • 什么是 IAT Hook?
  • 学习新工具(覆盖程序员绝大部分需求的工具)(zz)
  • 20250811 之所思 - 人生如梦
  • 2025牛客多校第七场 双生、象牙 个人题解 - CUC
  • 大模型部署与应用的典型场景及技术挑战
  • 全球语言全覆盖:一款强大的多语言客服系统
  • Verify my blogs in Follow
  • MX-2025 盖世计划 C 班 Day 9 复盘
  • 3.2~3.4.2数据类型关键词
  • 三星SAMSUNG SCX-4521F 一体机驱动
  • macos 开放3306端口
  • GAS_Aura-GameMode
  • telnet localhost 3306 -bash: telnet: command not found
  • Python面向对象实战之扑克游戏
  • vim常见操作
  • 可能是校内题单题解(20250811)
  • 无痕检测是否注册iMessage服务,iMessages数据筛选,iMessage蓝号检测完美实现
  • FWT 快速沃尔什变换