final关键字
核心概念
final是Java中的一个重要关键字,可以修饰类、方法和变量,提供了不可变性和性能优化的能力。理解final的使用场景和底层机制,是编写高质量Java代码的关键。
一、final修饰变量
1.1 基本用法
public class FinalDemo {
// 1. 编译期常量
public static final int CONSTANT = 100;
// 2. 运行时常量(必须在构造函数中初始化)
private final int runtimeConstant;
public FinalDemo(int value) {
this.runtimeConstant = value;
}
// 3. final局部变量
public void method() {
final int localFinal = 200;
// localFinal = 300; // ❌ 编译错误
}
}
1.2 引用类型的final
public class FinalReferenceDemo {
// final引用:引用不可变,但对象可以修改
private final List<String> list = new ArrayList<>();
public void modifyList() {
// ✅ 可以修改列表内容
list.add("Hello");
list.remove(0);
// ❌ 不能重新赋值引用
// list = new ArrayList<>(); // 编译错误
}
// final参数
public void processData(final User user) {
// user = new User(); // ❌ 编译错误
user.setName("New Name"); // ✅ 可以修改对象内部状态
}
}
1.3 final的内存语义
public class FinalMemoryDemo {
// final变量的内存可见性
private final int x;
private final int y;
public FinalMemoryDemo() {
x = 1; // 写入final变量
y = 2; // happens-before原则
}
public void method() {
// x和y的值对所有线程可见
System.out.println(x + y);
}
}
二、final修饰方法
2.1 防止方法重写
public class Parent {
// 不允许子类重写
public final void method() {
System.out.println("Cannot be overridden");
}
}
class Child extends Parent {
// ❌ 编译错误
// @Override
// public void method() { }
}
2.2 性能优化
public class OptimizationDemo {
// JVM可以内联final方法,提高性能
public final int calculate(int a, int b) {
return a + b;
}
}
三、final修饰类
3.1 阻止继承
// 不允许被继承
public final class ImmutableClass {
private final int value;
public ImmutableClass(int value) {
this.value = value;
}
}
// ❌ 编译错误
// class SubClass extends ImmutableClass { }
3.2 不可变类的设计
public final class Money {
private final int amount;
private final String currency;
public Money(int amount, String currency) {
this.amount = amount;
this.currency = currency;
}
// 只读方法
public int getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
// 创建新对象,而不是修改
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Cannot add different currencies");
}
return new Money(this.amount + other.amount, this.currency);
}
}
四、final的性能优化
4.1 编译器优化
public class OptimizationDemo {
// 编译器可以进行常量折叠
public static final int MAGIC_NUMBER = 42;
public int calculate() {
// 编译后可能直接替换为 return 84;
return MAGIC_NUMBER * 2;
}
}
4.2 JVM内联
public class InlineDemo {
// final方法更容易被JVM内联
public final int add(int a, int b) {
return a + b;
}
public void process() {
int result = add(10, 20); // 可能被直接替换
}
}
五、高频面试题
Q1: final和finally有什么区别?
答:
final:修饰不可变的变量、方法或类finally:异常处理中的finally块,无论是否异常都会执行
Q2: final变量必须在声明时初始化吗?
答:
- 静态final变量:必须在声明时或静态块中初始化
- 实例final变量:可以在声明、构造函数或初始化块中初始化
Q3: final修饰引用类型变量时什么意思?
答:
- 引用不可变:不能重新赋值
- 对象内部状态可以修改
- 类似于引用的"只读"
Q4: final方法的性能优势是什么?
答:
- JVM可以内联final方法
- 编译器可以进行更多优化
- 方法调用开销降低
Q5: 为什么String类是final的?
答:
- 线程安全
- 字符串常量池需要不可变性
- 防止被恶意继承和修改
六、最佳实践
✅ 推荐做法
// 1. 常量使用final
public static final double PI = 3.14159;
// 2. 不可变类设计
public final class ImmutableUser {
private final String name;
private final int age;
}
// 3. 方法性能优化
public final int calculate(int a, int b) {
return a + b;
}
❌ 避免做法
// 1. 避免过度使用final
public final class TooRestrictive {
// 过度限制,降低灵活性
}
// 2. final不等于完全不可变
public final class WeakImmutability {
private final List<String> list;
// list内容仍可以修改
}
相关链接
- 02-static关键字
- 01-继承与多态
- 不可变对象设计(含不可变对象专节)
记忆口诀
final修饰不可变,变量方法类为先
引用不能重新指,对象内部可更新
性能优化靠内联,编译器帮你加速间
不可继承不可改,安全高效是真谛
⬅️ 面向对象设计的SOLID原则 🏠 00-Java ➡️ static关键字
💬 评论