1. final 关键字 #
final 是 Java 中的一个重要修饰符,用于声明不可变性。
1.1 修饰类 #
- 被
final修饰的类是最终类,不能被继承 - 典型应用:
String、Math、System等核心类
// 定义 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 单例类(设计模式) #
单例模式确保一个类只能创建一个对象,并提供全局访问点
实现要点 #
- 构造器私有化(防止外部 new 对象)
- 定义静态变量保存唯一实例
- 提供静态方法返回实例
饿汉式单例(推荐) #
/**
* 饿汉式:类加载时就创建对象
* 优点:线程安全,实现简单
* 缺点:可能造成内存浪费
*/
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();
}
}
应用场景 #
- 配置管理器:全局配置对象
- 日志管理器:统一日志输出
- 数据库连接池:管理数据库连接
- 线程池:管理线程资源
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 | 状态、类型 | 模板模式 | 策略模式 |