在Java语法里, final关键字用在声明参数时, 该参数叫做常量; 否则叫做变量。
final关键字的作用是值(或引用)不可改, 但引用的对象可以改值。
常量的一般声明方式:
class SomeClass { final int SOME_CONSTANT1 = 1; final int SOME_CONSTANT2 = 2; ...... }
声明时为final参数赋初值, 这种情况下不能篡改。
但是声明final参数时不赋初值, 这种情况下是可以篡改的!!! 例如:
final int a; a = 1; 可以通过反射修改参数a的值。
为什么使用关键字后参数就是常量, 不能修改了呢???
其实final属性以及访问权限都对应一个二进制比特位, 在java.lang.reflect.Modifier.java里声明:
public class Modifier {
/**
* The {@code int} value representing the {@code private}
* modifier.
*/
public static final int PRIVATE = 0x00000002;
/**
* The {@code int} value representing the {@code protected}
* modifier.
*/
public static final int PROTECTED = 0x00000004;
/**
* The {@code int} value representing the {@code static}
* modifier.
*/
public static final int STATIC = 0x00000008;
/**
* The {@code int} value representing the {@code final}
* modifier.
*/
public static final int FINAL = 0x00000010;
.......
}
那么是否可以篡改函数、属性的访问特性呢? 答案是肯定的。 下面以修改final属性为例:
static class Test {
private final int a; //赋值后仍然可以该
private int b;
private final int c = 3; //改不了
Test(int param1, int param2) {
a = param1;
b = param2;
}
public int getValueA() {
return a;
}
public int getValueB() {
return b;
}
public int getValueC() { return c; }
}
/**
* 清除final属性, 及修改modifier参数
* @param field
*/
public static void removeFieldFinalModifier(final Field field) {
if (field == null) {
return;
}
try {
if (Modifier.isFinal(field.getModifiers())) {
final Field modifiersField = Field.class.getDeclaredField("modifiers");
final boolean doForceAccess = !modifiersField.isAccessible();
if (doForceAccess) {
modifiersField.setAccessible(true);
}
try {
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} finally {
if (doForceAccess) {
modifiersField.setAccessible(false);
}
}
}
} catch (final NoSuchFieldException ignored) {
// The field class contains always a modifiers field
} catch (final IllegalAccessException ignored) {
// The modifiers field is made accessible
}
}
public static void main(String[] args) {
Test obj = new Test(1, 2); //a等于1, b等于2
Class clz = Test.class;
System.out.println("final属性a篡改前:" + obj.getValueA());
System.out.println("非final属性b篡改前:" + obj.getValueB());
System.out.println("final属性c篡改前:" + obj.getValueC());
try {
Field fieldA = clz.getDeclaredField("a");
fieldA.setAccessible(true);
Field fieldB = clz.getDeclaredField("b");
fieldB.setAccessible(true);
Field fieldC = clz.getDeclaredField("c");
fieldC.setAccessible(true);
removeFieldFinalModifier(fieldA); //删除final限制
fieldA.setInt(obj, 11); //final属性a的值从1变为11
fieldB.setInt(obj, 22); //值变为22
removeFieldFinalModifier(fieldC); //删除final限制
fieldC.setInt(obj, 33); //无法篡改
System.out.println("---------------以下是结果----------------");
System.out.println("final属性a篡改后:" + obj.getValueA());
System.out.println("非final属性b篡改后:" + obj.getValueB());
System.out.println("final属性c篡改后:" + obj.getValueC());
} catch (Exception ex) {
ex.printStackTrace();
}
}
输出日志:
final属性a篡改前:1
非final属性b篡改前:2
final属性c篡改前:3
---------------以下是结果----------------
final属性a篡改后:11
非final属性b篡改后:22
final属性c篡改后:3