深耕JavaSe - 解析final关键字的作用

本文详细解析了Java中final关键字的用法,包括final修饰变量、方法和类的含义。final变量分为基本类型和引用类型,前者不可改变,后者引用不可变但对象内容可变。final方法不可被子类重写,final类则不能被继承。此外,满足特定条件的final变量可被编译器做“宏替换”。通过对final的深入理解,有助于提升代码的稳定性和设计的规范性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 被final修饰的变量不可以被改变

final修饰变量时,表示该变量一旦获得了初始值就不可被改变,即该final变量的值就不能被重新赋值。

1. final 修饰成员变量

final修饰的类成员变量必须在声明时或静态代码块中初始化;

final修饰的实例成员变量必须在声明时、非静态初始化块或构造器中初始化

final修饰的本地方法变量,必须使用前初始化,系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化。

public class Test {
    // 定义变量时赋初值
    final int a = 6;
    final String str;
    final int c;
    final static double d;
    final char ch;
    // 初始代码块,可以对实例Field赋予初值
    {
        str = "hello";
    }
    // 静态代码块,可以为类Field赋予初值
    static {
        d = 5.6;
    }
    // 构造方法,可以为实例Field赋予初值
    public Test(){
       c = 5;
    }
    // 普通方法中,不能为final成员变量赋初值
    public void changeFinal(){
        // ch = 'a';
    }
    // 普通方法中,不能为final局部变量赋初值
    public void testFinal(){
        final String s = "abc";
    }
}

2. final修饰基本类型变量和引用类型变量的区别

当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。

public class Main {
    public static void main(String[] args) {
        final int[] arr = {1,2,3,4};
        // 对数组元素进行排序,合法
        Arrays.sort(arr);
        // 对数组元素进行赋值,合法
        arr[2] = 5;
        // 对arr重新赋值,非法
        arr = null;
    }
}

使用final修饰的引用类型变量不能被重新赋值,但可以改变引用类型变量所引用对象的内容。例如上面arr变量所引用的数组对象,final修饰后的arr变量不能被重新赋值,但arr所引用数组的数组元素可以被改变。

2. 被final修饰的方法不可以被重写

如果出于某些原因,不希望子类重写父类的某个方法,则可以使用final修饰该方法。

Java提供的Object类里就有一个final方法:getClass(),因为Java不希望任何类重写这个方法,所以使用final把这个方法密封起来。但对于该类提供的toString()和equals()方法,都允许子类重写,因此没有使用final修饰它们。

3. 被final修饰的类不可以被继承

当子类继承父类时,将可以访问到父类内部数据,并可通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素。为了保证某个类不可被继承,则可以使用final修饰这个类。

4. 可执行“宏替换”的final变量

对一个final变量来说,不管它是类Field、实例Field,还是局部变量,只要该变量满足3个条件,这个final变量就不再是一个变量,而是相当于一个直接量:

(1) 使用final修饰符修饰;

(2) 在定义该final变量时指定了初始值;

(3) 该初始值可以在编译时就被确定下来。

public class Main {
    public static void main(String[] args) {
        // 定义了一个final局部变量,并在定义该final变量时指定初始值为5
        final int a=5;
        // 变量a其实根本不存在,当程序执行System.out.println(a);时,实际转换为执行System.out.println(5)。
        System.out.println(a);
    }
}

final修饰符的一个重要用途就是定义“宏变量”。当定义final变量时就为该变量指定了初始值,而且该初始值可以在编译时就确定下来,那么这个final变量本质上就是一个“宏变量”,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。

除了上面那种为final变量赋值时赋直接量的情况外,如果被赋的表达式只是基本的算术表达式或字符串连接运算,没有访问普通变量,调用方法,Java编译器同样会将这种final变量当成“宏变量”处理。

public class Main {
    public static void main(String[] args) {
        // 算术表达式
        final int a = 1+2;
        // 字符串连接运算
        String b = "hello" + "99";
        // 字符串连接运算中包含隐式类型(将数值转换为字符串)转换
        String c = "hello" + 99;

        // 编译器可以在编译时就确定a、b、c这3个变量的值,因此它们都是“宏变量”
        System.out.println(b==c); // true

        // 由于该变量的值需要调用String类的方法,因此编译器无法在编译时确定d的值,d不会被当成“宏变量”处理
        String d = "hello" + String.valueOf(99);
        System.out.println(b==d); // false
    }
}

其实final关键字在jvm,并发编程,异常中都有一定的作用,这个我们后面再深入补充,这里就先不发散了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我一直在流浪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值