跳过正文
Java面向对象高级编程—基础
  1. TP` Blog/

Java面向对象高级编程—基础

·9 分钟· loading ·
龙城飞将
作者
龙城飞将
最美的是月亮🌙……
目录
Java学习之旅 - 这篇文章属于一个选集。
§ 4: 本文

1. final 关键字
#

final 是 Java 中的一个重要修饰符,用于声明不可变性。

1.1 修饰类
#

  • final 修饰的类是最终类,不能被继承
  • 典型应用:StringMathSystem 等核心类
// 定义 final 类
public final class FinalClass {
    public void display() {
        System.out.println("这是一个最终类");
    }
}

// 编译错误:无法继承 final 类
// class SubClass extends FinalClass { }

1.2 修饰方法
#

  • final 修饰的方法不能被子类重写
  • 保证方法的行为在继承体系中保持一致
public class Parent {
    // final 方法
    public final void show() {
        System.out.println("这是父类的 final 方法");
    }
}

public class Child extends Parent {
    // 编译错误:无法重写 final 方法
    // public void show() { }
}

1.3 修饰变量
#

  • final 修饰的变量只能被赋值一次,成为常量
  • 修饰基本类型:值不可变
  • 修饰引用类型:引用地址不可变,但对象内容可以改变
public class FinalVariable {
    // 常量命名规范:全大写,下划线分隔
    public static final double PI = 3.14159;
    
    public void demo() {
        // 基本类型
        final int num = 10;
        // num = 20; // 编译错误
        
        // 引用类型
        final int[] arr = {1, 2, 3};
        arr[0] = 100;  // ✅ 可以修改数组内容
        // arr = new int[5]; // ❌ 不能改变引用
        
        final StringBuilder sb = new StringBuilder("Hello");
        sb.append(" World");  // ✅ 可以修改对象内容
        // sb = new StringBuilder(); // ❌ 不能改变引用
    }
}

1.4 final 关键字对比表
#

修饰对象 作用 典型应用场景
不能被继承 工具类、安全类(String)
方法 不能被重写 核心算法、安全方法
基本类型变量 值不可变 常量定义
引用类型变量 地址不可变 配置对象、依赖注入

2. 特殊类
#

Java 中有几种具有特殊用途的类设计:

  • 单例类:控制对象创建数量
  • 枚举类:定义固定的常量集合
  • 抽象类:定义模板和规范
  • 接口:定义行为契约

2.1 单例类(设计模式)
#

单例模式确保一个类只能创建一个对象,并提供全局访问点

实现要点
#

  1. 构造器私有化(防止外部 new 对象)
  2. 定义静态变量保存唯一实例
  3. 提供静态方法返回实例

饿汉式单例(推荐)
#

/**
 * 饿汉式:类加载时就创建对象
 * 优点:线程安全,实现简单
 * 缺点:可能造成内存浪费
 */
public class Singleton1 {
    // 1. 私有化构造器
    private Singleton1() {
        System.out.println("创建单例对象");
    }
    
    // 2. 定义静态变量保存唯一实例(类加载时创建)
    private static final Singleton1 instance = new Singleton1();
    
    // 3. 提供公共静态方法返回实例
    public static Singleton1 getInstance() {
        return instance;
    }
    
    public void showMessage() {
        System.out.println("这是单例对象的方法");
    }
}

懒汉式单例
#

/**
 * 懒汉式:第一次使用时才创建对象
 * 优点:延迟加载,节省内存
 * 缺点:需要考虑线程安全
 */
public class Singleton2 {
    private Singleton2() {}
    
    private static Singleton2 instance;
    
    // 加锁保证线程安全
    public static synchronized Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }
        return instance;
    }
}

使用示例
#

public class SingletonTest {
    public static void main(String[] args) {
        // 获取单例对象
        Singleton1 s1 = Singleton1.getInstance();
        Singleton1 s2 = Singleton1.getInstance();
        
        // 验证是同一个对象
        System.out.println(s1 == s2);  // true
        System.out.println(s1.hashCode() == s2.hashCode());  // true
        
        s1.showMessage();
    }
}

应用场景
#

  • 配置管理器:全局配置对象
  • 日志管理器:统一日志输出
  • 数据库连接池:管理数据库连接
  • 线程池:管理线程资源

单例模式 UML 类图


2.2 枚举类
#

枚举类是一种特殊的类,用于定义一组固定的常量对象

基本语法
#

修饰符 enum 枚举类名 {
    对象名称1, 对象名称2, 对象名称3;
    // 其他成员...
}

枚举特点
#

  • ✅ 第一行只能罗列常量名称(每个都是该枚举类的一个对象)
  • ✅ 枚举类都是 final 类,不能被继承
  • ✅ 构造器默认私有,不能对外创建对象
  • ✅ 枚举类继承自 java.lang.Enum

简单枚举
#

// 定义方向枚举
public enum Direction {
    UP, DOWN, LEFT, RIGHT;
}

// 定义季节枚举
public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

带属性和方法的枚举
#

/**
 * 定义星期枚举(带中文名称和是否工作日)
 */
public enum Week {
    // 枚举常量(必须放在第一行)
    MONDAY("星期一", true),
    TUESDAY("星期二", true),
    WEDNESDAY("星期三", true),
    THURSDAY("星期四", true),
    FRIDAY("星期五", true),
    SATURDAY("星期六", false),
    SUNDAY("星期日", false);
    
    // 枚举属性
    private final String name;
    private final boolean isWorkday;
    
    // 私有构造器
    private Week(String name, boolean isWorkday) {
        [this.name](http://this.name) = name;
        this.isWorkday = isWorkday;
    }
    
    // 公共方法
    public String getName() {
        return name;
    }
    
    public boolean isWorkday() {
        return isWorkday;
    }
}

使用示例
#

public class EnumTest {
    public static void main(String[] args) {
        // 1. 获取枚举常量
        Week today = Week.MONDAY;
        System.out.println(today);  // MONDAY
        
        // 2. 访问枚举属性
        System.out.println(today.getName());      // 星期一
        System.out.println(today.isWorkday());    // true
        
        // 3. 遍历所有枚举值
        System.out.println("\n所有星期:");
        for (Week w : Week.values()) {
            System.out.printf("%s - %s - %s%n", 
                w, w.getName(), w.isWorkday() ? "工作日" : "休息日");
        }
        
        // 4. 比较枚举
        Week day1 = Week.SATURDAY;
        Week day2 = Week.SATURDAY;
        System.out.println(day1 == day2);  // true(枚举常量是单例)
        
        // 5. switch 语句
        switch (today) {
            case MONDAY:
            case TUESDAY:
            case WEDNESDAY:
            case THURSDAY:
            case FRIDAY:
                System.out.println("工作日,加油!");
                break;
            case SATURDAY:
            case SUNDAY:
                System.out.println("周末,休息!");
                break;
        }
        
        // 6. 根据名称获取枚举
        Week friday = Week.valueOf("FRIDAY");
        System.out.println(friday.getName());  // 星期五
    }
}

枚举常用方法
#

方法 说明 示例
values() 返回所有枚举常量数组 Week.values()
valueOf(String) 根据名称获取枚举常量 Week.valueOf("MONDAY")
name() 获取枚举常量名称 [Week.MONDAY.name](http://Week.MONDAY.name)()
ordinal() 获取枚举常量索引位置 Week.MONDAY.ordinal()

应用场景
#

  • 状态管理:订单状态(待支付、已支付、已发货、已完成)
  • 类型分类:性别、级别、权限
  • 固定选项:星期、月份、方向
  • 配置常量:环境配置(开发、测试、生产)
// 订单状态枚举
public enum OrderStatus {
    PENDING("待支付"),
    PAID("已支付"),
    SHIPPED("已发货"),
    COMPLETED("已完成"),
    CANCELLED("已取消");
    
    private String description;
    
    OrderStatus(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

2.3 抽象类
#

使用 abstract 修饰的类,作为模板让子类继承和实现

抽象方法
#

  • 必须用 abstract 修饰
  • 只有方法签名,没有方法体
  • 必须定义在抽象类中
public abstract void methodName();

抽象类特点
#

特点 说明
✅ 可以有抽象方法 强制子类实现特定方法
✅ 可以有普通方法 提供通用功能实现
✅ 可以有成员变量 定义子类共享的属性
✅ 可以有构造器 供子类调用初始化
❌ 不能创建对象 只能作为父类被继承
⚠️ 子类必须重写所有抽象方法 除非子类也是抽象类

定义抽象类
#

/**
 * 抽象类:动物
 */
public abstract class Animal {
    // 普通成员变量
    private String name;
    private int age;
    
    // 构造器
    public Animal(String name, int age) {
        [this.name](http://this.name) = name;
        this.age = age;
    }
    
    // 普通方法(提供通用实现)
    public void sleep() {
        System.out.println(name + " 正在睡觉...");
    }
    
    // 抽象方法(强制子类实现)
    public abstract void eat();
    public abstract void makeSound();
    
    // Getter/Setter
    public String getName() {
        return name;
    }
}

继承抽象类
#

/**
 * 具体类:狗
 */
public class Dog extends Animal {
    private String breed;  // 品种
    
    public Dog(String name, int age, String breed) {
        super(name, age);  // 调用父类构造器
        this.breed = breed;
    }
    
    // 必须实现父类的抽象方法
    @Override
    public void eat() {
        System.out.println(getName() + " 正在吃狗粮");
    }
    
    @Override
    public void makeSound() {
        System.out.println(getName() + " 汪汪叫");
    }
    
    // 自己的方法
    public void guard() {
        System.out.println(getName() + " 正在看家");
    }
}

/**
 * 具体类:猫
 */
public class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }
    
    @Override
    public void eat() {
        System.out.println(getName() + " 正在吃鱼");
    }
    
    @Override
    public void makeSound() {
        System.out.println(getName() + " 喵喵叫");
    }
    
    public void catchMouse() {
        System.out.println(getName() + " 正在抓老鼠");
    }
}

使用示例
#

public class AbstractTest {
    public static void main(String[] args) {
        // ❌ 不能创建抽象类对象
        // Animal animal = new Animal("动物", 1);
        
        // ✅ 创建具体子类对象
        Dog dog = new Dog("旺财", 3, "金毛");
        [dog.eat](http://dog.eat)();         // 旺财 正在吃狗粮
        dog.makeSound();   // 旺财 汪汪叫
        dog.sleep();       // 旺财 正在睡觉...(继承自父类)
        dog.guard();       // 旺财 正在看家
        
        System.out.println();
        
        Cat cat = new Cat("咪咪", 2);
        [cat.eat](http://cat.eat)();         // 咪咪 正在吃鱼
        cat.makeSound();   // 咪咪 喵喵叫
        cat.sleep();       // 咪咪 正在睡觉...
        cat.catchMouse();  // 咪咪 正在抓老鼠
        
        System.out.println("\n--- 多态应用 ---");
        // ✅ 多态:父类引用指向子类对象
        Animal a1 = new Dog("小黑", 2, "拉布拉多");
        Animal a2 = new Cat("小白", 1);
        
        // 统一调用(实际执行子类实现)
        [a1.eat](http://a1.eat)();          // 小黑 正在吃狗粮
        [a2.eat](http://a2.eat)();          // 小白 正在吃鱼
    }
}

抽象类模板模式示例
#

/**
 * 模板模式:定义算法骨架,具体步骤由子类实现
 */
public abstract class BeverageTemplate {
    // 模板方法(final 防止子类修改)
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    
    // 通用步骤
    private void boilWater() {
        System.out.println("1. 烧开水");
    }
    
    private void pourInCup() {
        System.out.println("3. 倒入杯中");
    }
    
    // 抽象步骤(由子类实现)
    protected abstract void brew();
    protected abstract void addCondiments();
}

// 具体实现:茶
class Tea extends BeverageTemplate {
    @Override
    protected void brew() {
        System.out.println("2. 用沸水浸泡茶叶");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("4. 加柠檬");
    }
}

// 具体实现:咖啡
class Coffee extends BeverageTemplate {
    @Override
    protected void brew() {
        System.out.println("2. 用沸水冲泡咖啡");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("4. 加糖和牛奶");
    }
}

2.4 接口
#

使用 interface 定义,是一种完全抽象的类型,定义行为规范

基本语法
#

public interface 接口名 {
    // 成员变量(常量):public static final
    // 成员方法(抽象方法):public abstract
}

接口特点
#

  • 不能创建对象
  • 被类实现(implements)
  • 一个类可以实现多个接口(弥补单继承不足)
  • ✅ 成员变量默认是 public static final(常量)
  • ✅ 成员方法默认是 public abstract(抽象方法)
  • ✅ 接口可以多继承其他接口

定义接口
#

/**
 * 接口:飞行能力
 */
public interface Flyable {
    // 常量(public static final 可省略)
    int MAX_SPEED = 1000;
    
    // 抽象方法(public abstract 可省略)
    void fly();
    void land();
}

/**
 * 接口:游泳能力
 */
public interface Swimmable {
    void swim();
}

/**
 * 接口:说话能力
 */
public interface Speakable {
    void speak();
}

实现接口
#

/**
 * 类实现接口:必须实现所有抽象方法
 */
public class Bird implements Flyable {
    private String name;
    
    public Bird(String name) {
        [this.name](http://this.name) = name;
    }
    
    @Override
    public void fly() {
        System.out.println(name + " 在天空飞翔,最高速度:" + MAX_SPEED + "km/h");
    }
    
    @Override
    public void land() {
        System.out.println(name + " 降落到地面");
    }
}

/**
 * 一个类实现多个接口
 */
public class Duck implements Flyable, Swimmable {
    private String name;
    
    public Duck(String name) {
        [this.name](http://this.name) = name;
    }
    
    @Override
    public void fly() {
        System.out.println(name + " 飞行(速度较慢)");
    }
    
    @Override
    public void land() {
        System.out.println(name + " 降落");
    }
    
    @Override
    public void swim() {
        System.out.println(name + " 在水中游泳");
    }
}

/**
 * 超人类:继承父类 + 实现多个接口
 */
class Person {
    protected String name;
    
    public Person(String name) {
        [this.name](http://this.name) = name;
    }
    
    public void eat() {
        System.out.println(name + " 正在吃饭");
    }
}

public class Superman extends Person implements Flyable, Speakable {
    public Superman(String name) {
        super(name);
    }
    
    @Override
    public void fly() {
        System.out.println(name + " 像鸟儿一样自由飞翔!");
    }
    
    @Override
    public void land() {
        System.out.println(name + " 优雅降落");
    }
    
    @Override
    public void speak() {
        System.out.println(name + " 说:我来拯救世界!");
    }
}

使用示例
#

public class InterfaceTest {
    public static void main(String[] args) {
        // 1. 单接口实现
        Bird bird = new Bird("老鹰");
        [bird.fly](http://bird.fly)();
        [bird.land](http://bird.land)();
        
        System.out.println();
        
        // 2. 多接口实现
        Duck duck = new Duck("唐老鸭");
        [duck.fly](http://duck.fly)();
        duck.swim();
        [duck.land](http://duck.land)();
        
        System.out.println();
        
        // 3. 继承+多接口实现
        Superman superman = new Superman("超人");
        [superman.eat](http://superman.eat)();     // 继承自 Person
        [superman.fly](http://superman.fly)();     // 实现 Flyable
        superman.speak();   // 实现 Speakable
        
        System.out.println("\n--- 多态应用 ---");
        // 4. 接口多态
        Flyable f1 = new Bird("麻雀");
        Flyable f2 = new Duck("野鸭");
        Flyable f3 = new Superman("闪电侠");
        
        [f1.fly](http://f1.fly)();
        [f2.fly](http://f2.fly)();
        [f3.fly](http://f3.fly)();
    }
}

接口的作用优势
#

接口多继承
#

// 接口可以继承多个接口
public interface Vehicle extends Flyable, Swimmable {
    void drive();
}

// 实现类需要实现所有方法
public class Amphibian implements Vehicle {
    @Override
    public void fly() {
        System.out.println("水陆两栖:飞行模式");
    }
    
    @Override
    public void swim() {
        System.out.println("水陆两栖:游泳模式");
    }
    
    @Override
    public void drive() {
        System.out.println("水陆两栖:陆地行驶");
    }
}

接口冲突处理
#

interface A {
    default void show() {
        System.out.println("接口 A 的 show");
    }
}

interface B {
    default void show() {
        System.out.println("接口 B 的 show");
    }
}

// 实现多个接口时方法冲突,必须重写
class C implements A, B {
    @Override
    public void show() {
        System.out.println("类 C 重写的 show");
        // 可以选择调用特定接口的方法
        [A.super.show](http://A.super.show)();
        [B.super.show](http://B.super.show)();
    }
}

2.5 抽象类 vs 接口
#

相同点
#

特性 抽象类 接口
抽象形式
可以有抽象方法
不能创建对象
派生子类
必须重写抽象方法
支持多态

不同点
#

对比项 抽象类 接口
继承/实现 单继承(extends 多实现(implements
成员变量 可以有普通变量 只能有常量(public static final
构造器 可以有 不能有
方法类型 抽象+普通+静态 抽象+默认+静态(JDK8+)
访问修饰符 任意 只能 public
设计理念 is-a(是一个) can-do(能做)
使用场景 模板模式、代码复用 功能解耦、多重能力

相同点:

  • 都是抽象形式,都可以有抽象方法,都不能创建对象
  • 都是派生子类形式
  • 继承抽象类或者实现接口必须重写完抽象方法
  • 都支持多态,能够实现解耦合

不同点:

  • 抽象类可以定义全部普通成员,接口只能定义常量和抽象方法(JDK8新增的三个方法)
  • 抽象类只能单继承,但是类可以实现多个接口
  • 抽象类体现模板的思想,做父类实现代码复用性
  • 接口更适合做功能的解耦合

选择建议
#

// 抽象类:强调"是什么",代码复用
abstract class Vehicle {
    protected String brand;
    protected int speed;
    
    public Vehicle(String brand) {
        this.brand = brand;
    }
    
    // 通用方法
    public void start() {
        System.out.println(brand + " 启动");
    }
    
    // 抽象方法
    public abstract void run();
}

// 接口:强调"能做什么",功能定义
interface Chargeable {
    void charge();  // 充电能力
}

interface GPSEnabled {
    void navigate();  // 导航能力
}

// 具体类:继承抽象类 + 实现多个接口
class ElectricCar extends Vehicle implements Chargeable, GPSEnabled {
    public ElectricCar(String brand) {
        super(brand);
    }
    
    @Override
    public void run() {
        System.out.println(brand + " 电动行驶");
    }
    
    @Override
    public void charge() {
        System.out.println(brand + " 正在充电");
    }
    
    @Override
    public void navigate() {
        System.out.println(brand + " 开启 GPS 导航");
    }
}

3. 综合对比表
#

特性 final 类 枚举类 抽象类 接口
能否创建对象 ✅(固定对象)
能否被继承 ✅(多实现)
主要用途 不可变类 常量集合 模板复用 行为规范
典型应用 String、Math 状态、类型 模板模式 策略模式
Java学习之旅 - 这篇文章属于一个选集。
§ 4: 本文