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