Final关键字修饰的变量是否真的不能改变吗

本文探讨了Java中Final关键字修饰的变量是否真的不可改变,特别是静态常量和普通常量的区别。通过反射实验,展示了static final变量无法在运行时修改,而未初始化的final变量可以被反射改变,但已初始化的final变量则保持不变。

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

我们所知道的Final

在类上:该类不能被继承,其中所有的方法都不能被重写,但可以被重载, 所以不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,刚好final起冲突)        
在方法上: 该方法不能被重写,但是子类可以用父类中final修饰的方法       
在成员变量上: 该成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。
  • 通过上面的描述,我们知道如果被final修饰的成员变量是基本数据类型(例如int),那么该成员变量的值是不能被改变的。但是通过反射我们又验证了只被final修饰但没给定初始值的情况下的基本数据类型是可以通过反射来做到将其值改变的。【因为若同时被static和final修饰的话那值就绝对不可能被改变了】
  • final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变。
  • 我们知道在java编译期会做一些优化操作,比如替换一些final的不可变更的参数,所以那些引用了该被final修饰的变量就会被替换成具体的值。而我们现在要知道的是被final所修饰的变量到底是在那才赋值的。

那么static final和final 又有何区别呢?

  1. static修饰的属性强调它是只有一个,被所有对象所共享。
  2. final修饰的属性表明是一个常数(创建后不能被修改)。
  3. static final修饰的属性表示一旦给定值(常数),就不可修改,并且可以通过类名访问(因为只有一个)。

那么我们通过反射对static final修饰的属性及fianl修饰的属性进行修改看看会发生什么。

public class FinalTest1 {
    public static void main(String args[]) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        FinalTest finalTest = new FinalTest(1)或者new FinalTest();
        Field a = FinalTest.class.getDeclaredField("a");
        a.setAccessible(true);
        a.setInt(finalTest,3);
        System.out.println(a.get(finalTest));
        System.out.println(finalTest.getA());
    }
}

①当static final修饰的变量没有给定初始值的时候,结果是报错的。①的图片
②当static final有赋予初始值的时候

public class FinalTest {
    static private final int a=1 ; 
    public int getA(){
        return a;
    }
}
结果是报错,解释原因:
Exception in thread "main" java.lang.IllegalAccessException: Can not set static final int field com.gwok.test.FinalTest.a to (int)3
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:100)
    at sun.reflect.UnsafeQualifiedStaticIntegerFieldAccessorImpl.setInt(UnsafeQualifiedStaticIntegerFieldAccessorImpl.java:129)
    at java.lang.reflect.Field.setInt(Field.java:949)
    at com.gwok.test.FinalTest1.main(FinalTest1.java:10)

③当final没给定初始值的时候

public class FinalTest {
     private final int a ;

    public FinalTest(int a) {
        this.a = a;
    }
    public int getA(){
        return a;
    }
}
结果如下
    3
    3

④当final给定初始值的时候

public class FinalTest {   
	private final int a =1;
	public int getA(){
	    return a;    
	}
}
结果如下
	3
	1

总结:通过上面的试验,我们发现当变量被static final所修饰时,该变量的值是不能够被改变的,而且该变量必须给予初始值;对于只被final所修饰的变量在定义的时候没有给定初始值的情况下是能够通过反射来改变其代码运行期间所赋予的值,而对于在定义的时候已经给定初始值的情况下即使通过反射也无法改变其值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值