发布于2026-07-19 阅读(0)
扫一扫,手机访问
在Ja va开发里,有一个关键字几乎天天都会碰到,但越是常见的东西,越容易藏着一些容易忽略的细节。没错,说的就是final。表面上看,它只是“最终的、不可修改的”这么简单,但实际用起来,变量、方法、类,三个场景各有各的讲究,新手和老手都容易在这些地方翻车。
这篇文章会从final的三个核心使用场景——修饰变量、修饰方法、修饰类——入手,配合实战代码和容易踩坑的细节,最后再补上几道高频面试题。不管你是刚入门,还是想巩固基础备战面试,读完应该会有收获。
这里先划个重点:final的核心思想是“一旦定义,不可改变”。但注意,这个“不可改变”在不同场景下,含义可是完全不一样的。接下来一个一个说清楚。
final是Ja va里一个非访问修饰符,中文意思就是“最终的、不可变的”。它的作用很明确:一是保证代码的安全性,二是提升可读性和可维护性。什么意思呢?就是明确告诉其他人,这个变量、这个方法或者这个类,是不允许被随便动的。
具体来说,final可以修饰三种东西:变量、方法、类。下面逐一拆解。
final修饰变量时,含义是“该变量为常量,一旦赋值,无法再修改”。这个“不可修改”要分两种情况来看,基本数据类型和引用数据类型,完全是两码事,也是新手最容易搞混的地方。
先看基本数据类型,像int、char、double这些。一旦你用final修饰,变量的值就彻底锁死了,再想改?编译器直接报错。
public class FinalVariableDemo {
public static void main(String[] args) {
// 1. 局部变量(方法内):声明时直接赋值
final int MAX_AGE = 120; // 常量命名规范:全大写,单词间用下划线分隔
// MAX_AGE = 130; // 编译报错:无法为最终变量分配值
// 2. 成员变量(类内、方法外):两种赋值方式,二选一
final String NAME = "Ja va学习者"; // 方式1:声明时直接赋值
final int SCORE; // 方式2:构造器中赋值(必须赋值,否则编译报错)
// 构造器赋值
SCORE = 95;
// SCORE = 100; // 编译报错:已赋值,无法修改
}
}
重点来了!final修饰引用类型,比如对象、数组,锁住的是那个“引用地址”——也就是这个变量不能再指向别的对象了。但对象本身内部是怎么样的,它管不着,你可以随便改里面的属性值。
public class FinalReferenceDemo {
public static void main(String[] args) {
// final修饰数组(引用类型)
final int[] ARR = {1, 2, 3};
ARR[0] = 100; // 允许:修改数组内部元素的值
// ARR = new int[]{4,5,6}; // 编译报错:无法修改引用地址
// final修饰对象(引用类型)
final Person person = new Person("张三", 20);
person.setAge(21); // 允许:修改对象内部属性
// person = new Person("李四", 22); // 编译报错:无法修改引用地址
}
}
// 自定义Person类
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// setter方法:修改对象内部属性
public void setAge(int age) {
this.age = age;
}
}
实际开发中,final变量的应用场景其实很广:
举个实战例子,比如验证码功能:
// 全局常量:验证码字符池(固定不变,用final+static修饰) public static final String CODE_POOL = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 全局常量:验证码固定长度(不可修改) public static final int CODE_LENGTH = 4;
说完变量,再来看方法。final修饰方法时,意味着“该方法不能被子类重写”。注意,不能重写,但可以继承和调用,两者不冲突。
什么时候用?父类里那些逻辑已经固定、不希望子类随便改的方法,比如工具类的核心方法、通用逻辑,就可以用final锁住,防止子类重写后破坏设计意图。
// 父类
class Parent {
// final修饰方法,不能被子类重写
public final void showInfo() {
System.out.println("父类的固定逻辑,不可修改");
}
// 普通方法,可被子类重写
public void commonMethod() {
System.out.println("父类的普通方法");
}
}
// 子类
class Son extends Parent {
// 报错:Cannot override the final method from Parent
// @Override
// public void showInfo() {}
// 允许:重写普通方法
@Override
public void commonMethod() {
System.out.println("子类重写父类的普通方法");
}
}
两个小细节:第一,final方法不能被重写,但可以被重载(重载是方法名相同、参数列表不同,别搞混了);第二,private方法默认就是final的,因为子类根本访问不到,没必要再显式加final。
最后来看final修饰类。这个就很好理解了,final类就是“最终类”,不能再被继承。比如Ja va里的String、Math、System,全是final类。
为什么这么设计?要么是类的逻辑已经完整,不需要扩展;要么是为了安全,防止子类继承后篡改核心逻辑。比如String类,如果可以被继承,那字符串常量池的复用机制就可能被破坏,后果很严重。
// final修饰类,不能被继承
final class FinalClass {
public void show() {
System.out.println("final类的方法");
}
}
// 报错:Cannot inherit from final class FinalClass
// class SubClass extends FinalClass {}
注意两点:第一,final类里的所有方法,默认都是final的(因为类都不能被继承了,方法自然也没法重写,所以不用再显式加final);第二,final类可以继承别的类,比如String继承自Object,但别人不能继承它。
final是面试里的常客,下面这三道题几乎每次都会碰到,建议提前准备好。
这个问题其实前面已经说清楚了。final修饰引用变量,限制的是引用地址不能变,也就是变量不能再指向新的对象。但对象本身是独立的,它内部的属性值不受final限制,该改还是能改。
核心原因有两个:一是安全性,防止String被继承后篡改核心逻辑,避免字符串内容被意外修改(比如黑客改密码、改接口参数);二是效率,String类实现了常量池,final保证了字符串不可变,常量池才能正常复用,程序运行效率才能提上去。
说到这,final的用法基本就讲完了。最后简单总结一下,方便记忆:
final是Ja va基础里的重点,也是面试高频考点。建议多写几段代码练练手,尤其是“引用类型变量”的修饰细节,搞清楚了,以后踩坑的概率就小多了。
上一篇:如何分析Golang日志
下一篇:JS日志中如何处理内存泄漏
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8