第14篇:Java final关键字详解
📌 系列导航 :《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第13篇:JDK和JRE、final与static、堆和栈|
➡️ 下一篇:第15篇:Java控制流程语句
一、核心知识点
final修饰类:不能被继承final修饰方法:不能被重写(但可以被重载)final修饰变量:基本类型值不可变,引用类型引用不可变(但对象内部可变)- 空白
final:声明时不赋值,必须在构造方法中赋值 static final:类常量,命名全大写,下划线分隔
二、通俗讲解(1分钟开心学)
1. final修饰类
表示这个类是"最终版",不允许被继承。比如String类就是final的,所以你不能写class MyString extends String。
为什么String要设计成final?
- 安全性:防止子类恶意篡改字符串行为。
- 常量池:
final保证了字符串不变性,可以让相同内容的字符串共享对象。 - 线程安全:不可变对象天然线程安全。
2. final修饰方法
表示这个方法不能被子类重写。常在模板方法模式中使用,把骨架方法声明为final,让子类只能重写某些步骤。
3. final修饰变量
- 基本类型:值不能改变,名副其实的常量。
- 引用类型 :引用地址不能变,但对象内部属性可以变(除非对象本身是不可变的,如
String)。
4. 空白final
声明时不给值,但在所有的构造方法中必须赋值。这提供了一种灵活性:每个对象可以有不同的常量值,但一旦构造完成就不能改变。
5. static final
类常量,通常用大写字母加下划线命名,例如public static final double PI = 3.14;,在类加载时初始化,全局唯一。
三、实操代码案例 + 场景说明
场景:定义一个"人"类,每个人有唯一的身份证号(一旦创建不能修改),且有一个通用的最大年龄常量。
java
public class Person {
// 类常量(static final)
public static final int MAX_AGE = 150;
// 空白final实例变量:每个对象只能赋值一次
private final String idCard; // 身份证号
private String name;
public Person(String idCard, String name) {
this.idCard = idCard; // 必须在构造方法中赋值
this.name = name;
}
// 不允许修改身份证号,所以没有setIdCard()
public String getIdCard() { return idCard; }
public void setName(String name) { this.name = name; }
// final方法:子类不能重写
public final void showId() {
System.out.println("身份证:" + idCard);
}
}
// final类示例
final class SecurityUtil {
// 工具类,不希望被继承
public static void encrypt(String data) { }
}
// class MySecurity extends SecurityUtil {} // 编译错误,不能继承final类
final引用变量陷阱演示:
java
final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 可以,对象内部改变了
System.out.println(sb); // Hello World
// sb = new StringBuilder("New"); // 编译错误,引用不能指向新对象
四、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
认为final数组或集合内容不可变 |
错误理解,数组元素、集合元素仍可修改 | 需要不可变集合用Collections.unmodifiableList |
空白final在某个构造方法中忘记赋值 |
编译错误 | 确保所有构造方法都赋值 |
final方法被误认为效率一定更高 |
早期优化,现代JVM会自动内联 | 优先关注设计,而非性能 |
final类中所有方法自动成为final |
是的,但理解即可 | 不需要额外加final |
五、面试高频考点
Q1:final、finally、finalize的区别?
final是关键字,用于限制类、方法、变量;finally是异常处理的最后执行块;finalize是Object的方法,GC前调用(已弃用)。
Q2:String为什么要设计成final?
- 安全性(防止继承后篡改);2. 字符串常量池需要不可变性;3. 天然线程安全;4. hashCode可缓存提高性能。
Q3:final int[] arr = {1,2,3}; arr[0]=10; 合法吗?为什么?
合法。
arr引用不可变,但数组元素可变。只有数组引用本身不能指向新数组。
六、练习题
- 代码填空 :写出一个带有空白
final变量id的类,要求在构造方法中赋值。 - 设计 :为什么工具类(如
Math)常常用final类 + 私有构造方法?尝试实现一个简单的工具类。 - 判断 :
final Person p = new Person(); p = new Person();能否编译通过?
📊 你的学习进度
- 当前:第10篇 / 共44篇 · 第二阶段:核心语法与面向对象(第5~20篇)
- ✅ 已完成:第1~9篇
- 📖 正在学:第10篇
- ⏳ 待学习:第11~44篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!
👉 下一篇预告
《Java控制流程语句》
内容简介:if-else、switch-case(含箭头语法)、for/while/do-while循环,break/continue/return跳转。
💡 学完这篇,你将掌握所有流程控制语句,能写出任何逻辑的程序。
📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注 ,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!