十一、Java 入门必学:final、单例、枚举、抽象类、接口

目录

一、final 关键字

1. 修饰变量:变成 “常量”

2. 修饰方法:禁止子类重写

3. 修饰类:禁止被继承

核心总结

二、单例设计模式

1. 饿汉式单例:“饿了就先吃”(立即加载)

2. 懒汉式单例:“需要时再吃”(延迟加载)

饿汉式 vs 懒汉式

三、枚举

1. 认识枚举类

2. 枚举的应用场景

四、抽象类

1. 抽象类的基本规则

2. 抽象类的好处

3. 模板方法设计模式

抽象类的应用场景

五、接口

1. 认识接口

2. 接口的好处

3. JDK8 新增的三个方法

4. 接口的注意事项

接口 vs 抽象类

总结


一、final 关键字

final在 Java 中意为 “最终的、不可改变的”,可以修饰变量、方法、类,核心作用是限制修改,也是定义 “常量” 的核心关键字。

1. 修饰变量:变成 “常量”

  • final修饰的变量,赋值后就不能修改。
  1. 局部变量:声明后可以先不赋值,但只能赋值一次
  2. 成员变量:必须在声明时 / 构造方法中赋值,且赋值后不可变;
  3. 常量命名规范:全大写,多个单词用下划线分隔(如MAX_SCORE)。

代码示例

public class FinalDemo {
    // 1. 成员常量:声明时直接赋值
    public static final int MAX_SCORE = 100; // 全局常量(常用static+final)
    private final String USER_NAME; // 成员常量,构造方法中赋值

    // 构造方法中给final成员变量赋值
    public FinalDemo(String userName) {
        this.USER_NAME = userName; // 只能赋值一次
    }

    public void testFinalVar() {
        // 2. 局部常量:声明后赋值,且只能赋值一次
        final int age;
        age = 18;
        // age = 20; // 报错:final变量赋值后不可修改

        System.out.println(MAX_SCORE); // 输出100
        System.out.println(USER_NAME); // 输出构造方法传入的值
    }

    public static void main(String[] args) {
        FinalDemo demo = new FinalDemo("张三");
        demo.testFinalVar();
        // FinalDemo.MAX_SCORE = 90; // 报错:常量不可修改
    }
}

2. 修饰方法:禁止子类重写

  • final修饰的方法,子类不能重写(防止核心逻辑被篡改)。

代码示例

class Parent {
    public final void sayHello() {
        System.out.println("你好");
    }
}

class Child extends Parent {
    // @Override // 报错:无法重写final方法
    // public void sayHello() {}
}

3. 修饰类:禁止被继承

  • final修饰的类,不能有子类(比如 Java 自带的String类就是 final 的,保证字符串不可变)。

代码示例

final class FinalClass {}
// class SubClass extends FinalClass {} // 报错:无法继承final类

核心总结

final的核心是 “不可变”:

  1. 变量→常量(赋值后不能改);
  2. 方法→不能被重写;
  3. 类→不能被继承。

二、单例设计模式

单例模式是 Java 最常用的设计模式之一,核心目标:让一个类在程序运行期间,只能创建一个对象

常见的单例模式有两种实现方式:饿汉式、懒汉式。

1. 饿汉式单例:“饿了就先吃”(立即加载)

  • 类加载时就创建好实例,不管后续是否使用(优点:线程安全;缺点:可能浪费内存)。

代码示例

// 饿汉式单例
public class HungrySingleton {
    // 1. 私有构造方法:禁止外部new对象
    private HungrySingleton() {}

    // 2. 类加载时就创建唯一实例(静态变量)
    private static final HungrySingleton INSTANCE = new HungrySingleton();

    // 3. 提供公共方法获取实例
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }

    // 测试方法
    public void sayHi() {
        System.out.println("饿汉式单例:我是唯一的实例");
    }

    public static void main(String[] args) {
        // 获取两个实例,判断是否是同一个
        HungrySingleton s1 = HungrySingleton.getInstance();
        HungrySingleton s2 = HungrySingleton.getInstance();
        System.out.println(s1 == s2); // 输出true:同一个对象
    }
}

2. 懒汉式单例:“需要时再吃”(延迟加载)

  • 类加载时不创建实例,只有第一次调用getInstance()时才创建(优点:节省内存;缺点:基础版非线程安全)。

代码示例

// 懒汉式单例(基础版,非线程安全)
public class LazySingleton {
    // 1. 私有构造方法
    private LazySingleton() {}

    // 2. 声明实例变量,初始为null
    private static LazySingleton INSTANCE = null;

    // 3. 调用时才创建实例
    public static LazySingleton getInstance() {
        if (INSTANCE == null) { // 为空才创建
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }

    public void sayHi() {
        System.out.println("懒汉式单例:我是唯一的实例");
    }

    public static void main(String[] args) {
        LazySingleton s1 = LazySingleton.getInstance();
        LazySingleton s2 = LazySingleton.getInstance();
        System.out.println(s1 == s2); // 输出true
    }
}

饿汉式 vs 懒汉式

特性饿汉式懒汉式
加载时机类加载时创建第一次调用时创建
线程安全安全不安全
内存占用启动时占用,可能浪费按需加载,更节省

三、枚举

枚举(enum)是 Java 5 新增的特性,本质是 “特殊的类”,用于定义一组固定的、有限的常量,相比普通常量更安全、更易读。

1. 认识枚举类

  • enum关键字声明,里面的每个值都是枚举类的实例(默认public static final)。

代码示例

// 定义枚举类:季节
public enum Season {
    // 枚举常量(每个都是Season的实例)
    SPRING("春天", "春暖花开"),
    SUMMER("夏天", "烈日炎炎"),
    AUTUMN("秋天", "秋高气爽"),
    WINTER("冬天", "寒风刺骨");

    // 枚举类的成员变量(自定义属性)
    private final String name;
    private final String desc;

    // 枚举的构造方法:必须私有(默认也是私有)
    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    // 提供get方法(枚举常量不可修改,无需set)
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    // 测试枚举
    public static void main(String[] args) {
        // 1. 直接使用枚举常量
        Season spring = Season.SPRING;
        System.out.println(spring.getName()); // 输出:春天
        System.out.println(spring.getDesc()); // 输出:春暖花开

        // 2. 遍历所有枚举常量
        for (Season season : Season.values()) {
            System.out.println(season + ":" + season.getDesc());
        }

        // 3. 枚举的switch用法(更简洁)
        switch (spring) {
            case SPRING:
                System.out.println("当前是春天");
                break;
            case SUMMER:
                System.out.println("当前是夏天");
                break;
            // 其他case...
        }
    }
}

2. 枚举的应用场景

  1. 固定状态:订单状态(待支付、已支付、已取消)、用户状态(正常、禁用、锁定);
  2. 有限选项:星期(周一到周日)、季节、性别;
  3. 替代常量:相比public static final int SPRING = 1,枚举更安全,不会传错值;
  4. 实现单例:枚举是实现单例的最佳方式。

四、抽象类

抽象类用abstract关键字声明,是 “不完整的类”—— 里面可以包含抽象方法(只有声明,没有实现) 和普通方法,核心作用是 “定义模板,让子类实现细节”

1. 抽象类的基本规则

  1. 抽象类不能被实例化(不能new),只能被继承
  2. 包含抽象方法的类,必须是抽象类;
  3. 子类继承抽象类后,必须实现所有抽象方法(除非子类也是抽象类)。

代码示例

// 抽象类:动物
public abstract class Animal {
    // 普通方法(有实现)
    public void breathe() {
        System.out.println("所有动物都要呼吸");
    }

    // 抽象方法(只有声明,没有实现)
    public abstract void makeSound();
}

// 子类:狗(实现抽象方法)
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("小狗汪汪叫");
    }
}

// 子类:猫(实现抽象方法)
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("小猫喵喵叫");
    }
}

// 测试
class TestAnimal {
    public static void main(String[] args) {
        // Animal animal = new Animal(); // 报错:抽象类不能实例化
        Animal dog = new Dog();
        dog.breathe(); // 输出:所有动物都要呼吸
        dog.makeSound(); // 输出:小狗汪汪叫

        Animal cat = new Cat();
        cat.makeSound(); // 输出:小猫喵喵叫
    }
}

2. 抽象类的好处

  1. 代码复用:抽象类中的普通方法可以被所有子类复用(比如上面的breathe());
  2. 约束子类:抽象方法强制子类实现核心逻辑(比如所有动物都要实现makeSound(),保证子类有统一的行为);
  3. 定义骨架:结合 “模板方法模式”,固定核心流程,子类只改细节。

3. 模板方法设计模式

  • 抽象类定义一个 “模板方法”,流程中的可变步骤交给子类实现。

代码示例

// 抽象类:饮品制作模板
public abstract class DrinkTemplate {
    // 模板方法:固定制作流程(final防止子类修改)
    public final void makeDrink() {
        boilWater(); // 步骤1:烧水(固定)
        brew(); // 步骤2:冲泡(可变,子类实现)
        pourInCup(); // 步骤3:倒入杯中(固定)
        addCondiments(); // 步骤4:加调料(可变,子类实现)
    }

    // 固定方法:烧水
    private void boilWater() {
        System.out.println("烧开水(100℃)");
    }

    // 固定方法:倒入杯中
    private void pourInCup() {
        System.out.println("将饮品倒入杯中");
    }

    // 抽象方法:冲泡(子类实现)
    public abstract void brew();

    // 抽象方法:加调料(子类实现)
    public abstract void addCondiments();
}

// 子类:制作咖啡
class Coffee extends DrinkTemplate {
    @Override
    public void brew() {
        System.out.println("冲泡咖啡粉");
    }

    @Override
    public void addCondiments() {
        System.out.println("加牛奶和糖");
    }
}

// 子类:制作茶
class Tea extends DrinkTemplate {
    @Override
    public void brew() {
        System.out.println("冲泡茶叶");
    }

    @Override
    public void addCondiments() {
        System.out.println("加柠檬");
    }
}

// 测试
class TestDrink {
    public static void main(String[] args) {
        DrinkTemplate coffee = new Coffee();
        System.out.println("制作咖啡:");
        coffee.makeDrink(); // 按模板流程制作咖啡

        System.out.println("========");

        DrinkTemplate tea = new Tea();
        System.out.println("制作茶:");
        tea.makeDrink(); // 按模板流程制作茶
    }
}

输出结果

制作咖啡:
烧开水(100℃)
冲泡咖啡粉
将饮品倒入杯中
加牛奶和糖
========
制作茶:
烧开水(100℃)
冲泡茶叶
将饮品倒入杯中
加柠檬

抽象类的应用场景

  1. 多个类有共同的核心流程,但细节不同(比如上面的饮品制作);
  2. 需要定义统一的父类,约束子类的行为,但又不想让父类被实例化;
  3. 代码复用 + 行为约束的场景。

五、接口

接口(interface)是 Java 中 “纯抽象” 的规范,核心作用是定义契约(规则),让实现类遵守规则,是实现 “多态” 和 “解耦” 的核心

1. 认识接口

  1. interface关键字声明;
  2. JDK8 前:只能包含public static final常量 + public abstract方法;
  3. JDK8 后:新增默认方法、静态方法、私有方法;
  4. 类用implements实现接口,必须实现所有抽象方法(除非是抽象类)。

代码示例

// 定义接口:跑
public interface Runable {
    // 接口中的常量(默认public static final)
    int MAX_SPEED = 100;

    // 抽象方法(默认public abstract)
    void run();
}

// 实现类:人
class Person implements Runable {
    @Override
    public void run() {
        System.out.println("人用双腿跑,最高速度:" + MAX_SPEED);
    }
}

// 实现类:汽车
class Car implements Runable {
    @Override
    public void run() {
        System.out.println("汽车用轮子跑,最高速度:" + MAX_SPEED);
    }
}

// 测试
class TestRunable {
    public static void main(String[] args) {
        Runable person = new Person();
        person.run(); // 输出:人用双腿跑,最高速度:100

        Runable car = new Car();
        car.run(); // 输出:汽车用轮子跑,最高速度:100
    }
}

2. 接口的好处

  1. 解耦:接口定义规则,实现类负责实现,修改实现类不影响调用方;
  2. 多实现:Java 类只能单继承,但可以实现多个接口(弥补单继承的不足);
  3. 标准化:统一接口,不同实现类遵循同一规则;
  4. 多态:接口引用指向实现类对象,提高代码灵活性。

3. JDK8 新增的三个方法

  • JDK8 为接口新增了 3 种方法,让接口更灵活(不用强制所有实现类修改):
方法类型关键字特点
默认方法default有方法体,实现类可重写,也可直接使用
静态方法static有方法体,只能通过接口名调用(不能被实现类重写)
私有方法private有方法体,只能在接口内部调用(供默认方法 / 静态方法复用)

代码示例

public interface JDK8Interface {
    // 1. 抽象方法
    void abstractMethod();

    // 2. 默认方法
    default void defaultMethod() {
        System.out.println("接口默认方法");
        privateMethod(); // 调用私有方法
    }

    // 3. 静态方法
    static void staticMethod() {
        System.out.println("接口静态方法");
        privateStaticMethod(); // 调用私有静态方法
    }

    // 4. 私有方法(非静态)
    private void privateMethod() {
        System.out.println("接口私有方法:供默认方法复用");
    }

    // 5. 私有静态方法
    private static void privateStaticMethod() {
        System.out.println("接口私有静态方法:供静态方法复用");
    }
}

// 实现类
class JDK8Impl implements JDK8Interface {
    @Override
    public void abstractMethod() {
        System.out.println("实现抽象方法");
    }

    // 可选:重写默认方法
    @Override
    public void defaultMethod() {
        System.out.println("重写接口的默认方法");
    }
}

// 测试
class TestJDK8Interface {
    public static void main(String[] args) {
        JDK8Interface impl = new JDK8Impl();
        impl.abstractMethod(); // 输出:实现抽象方法
        impl.defaultMethod(); // 输出:重写接口的默认方法

        // 静态方法只能通过接口名调用
        JDK8Interface.staticMethod(); // 输出:接口静态方法 + 接口私有静态方法
    }
}

4. 接口的注意事项

  1. 接口不能被实例化(不能new);
  2. 接口的成员:
    • 变量:默认public static final(必须初始化);
    • 方法(JDK8 前):默认public abstract
  3. 一个类可以实现多个接口(用逗号分隔);
  4. 接口可以继承多个接口(用extends);
  5. 默认方法冲突:如果实现类同时实现两个接口,且接口有同名默认方法,必须重写该方法。

接口 vs 抽象类

特性抽象类接口
关键字abstract classinterface
继承 / 实现类用 extends 单继承类用 implements 多实现
方法可包含抽象方法 + 普通方法JDK8 前:只有抽象方法;JDK8 后:可包含默认 / 静态 / 私有方法
成员变量可定义任意变量只能是 public static final 常量
构造方法有构造方法(不能实例化)无构造方法
核心作用代码复用 + 定义骨架定义契约 + 解耦
使用场景子类有共同的父类,共享代码不同类需要遵守同一规则,解耦

总结

  1. final修饰变量→常量、修饰方法→不可重写、修饰类→不可继承;
  2. 单例模式:饿汉式(立即加载,线程安全)、懒汉式(延迟加载,基础版非线程安全),核心是保证类只有一个实例;
  3. 枚举:定义固定常量集,类型安全,适合状态 / 选项类场景;
  4. 抽象类:包含抽象方法,不能实例化,模板方法模式是经典应用,核心是 “骨架 + 可变细节”;
  5. 接口:定义契约,支持多实现,JDK8 新增默认 / 静态 / 私有方法,和抽象类的核心区别是 “契约 vs 复用”。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值