假设咱们有以下一个类,咱们要利用反射来对其成员变量就行修改:java
- class Entity {
- public int i = 1;
- }
通常咱们会这么做:
- try {
- Entity e = new Entity();
- System.out.println("before: " + e.i);
-
- Field f = Entity.class.getDeclaredField("i");
- f.setInt(e, 2);
- // 或者这样
- //f.set(e, 2);// java会自动装箱拆箱
-
- System.out.println("after: " + e.i);
- } catch (Exception e) {
- e.printStackTrace();
- }
结果输出:
- before: 1
- after: 2
可是若是咱们的成员变量是final呢?
- class Entity {
- public final int i = 1;
- }
咱们再用上面的方式来进行修改值,发现出异常了:
java.lang.IllegalAccessException: Can not set final int field com.test.Entity.i to (int)2
那咱们该怎么办呢?咱们能够修改为员变量的final修饰符,使其变为public int i = 1;具体方法以下:
- try {
- Entity e = new Entity();
- System.out.println("before: " + e.i);
-
- Field f = Entity.class.getDeclaredField("i");
-
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
-
- // 输出17:表示修饰符为:public final
- System.out.println(f.getModifiers());
-
- /* 这里就是要修改修饰符了,至于为何是f.getModifiers() & ~Modifier.FINAL,你们看一下Modifier的源码就知道了*/
- modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
-
- // 输出1:表示修饰符已经被修改成:public
- System.out.println(f.getModifiers());
-
- f.setAccessible(true);
-
- f.setInt(e, 2);
- //f.set(e, 3);
-
- System.out.println("after: " + e.i);
- } catch (Exception e) {
- e.printStackTrace();
- }
没有抛出异常了,可是确没有出现咱们想要的结果,输出为:
- before: 1
- 17
- 1
- after: 1
这是为何呢?咱们稍微修改下Entity的代码以下:
- class Entity {
- public final Integer i = 1;
- }
而后再执行,发现结果已经被修改了:
- before: 1
- 17
- 1
- after: 3
说明我能够对对象数据类型进行修改,而不能对基本数据类型进行修改, 咱们再来试试String类型的:
- class Entity {
- public final String s = "a";
- }
- try {
- Entity e = new Entity();
- System.out.println("before: " + e.s);
-
- Field f = Entity.class.getDeclaredField("s");
-
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
-
- System.out.println(f.getModifiers());
-
- modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
-
- System.out.println(f.getModifiers());
-
- f.setAccessible(true);
-
- //f.setInt(e, 2);
- f.set(e, "b");
-
- System.out.println("after: " + e.s);
- } catch (Exception e) {
- e.printStackTrace();
- }
结果输出:
- before: a
- 17
- 1
- after: a
咦?居然木有改变?咱们再对Entity稍微改动下:
- class Entity {
- public final String s = new String("a");
- }
结果输出:
- before: a
- 17
- 1
- after: b
总结一下,对于final修改的成员变量,基本数据以及public final String s = "a";这种方式不可被修改
而对于对象数据类型是能够突破final限制进行修改的。