• 利用反射对修饰符为final的成员变量进行修改


    利用反射对修饰符为final的成员变量进行修改

    假设咱们有以下一个类,咱们要利用反射来对其成员变量就行修改:java

      1. class Entity {
      2. public int i = 1;
      3. }

    通常咱们会这么做:

      1. try {
      2. Entity e = new Entity();
      3. System.out.println("before: " + e.i);
      4. Field f = Entity.class.getDeclaredField("i");
      5. f.setInt(e, 2);
      6. // 或者这样
      7. //f.set(e, 2);// java会自动装箱拆箱
      8. System.out.println("after: " + e.i);
      9. } catch (Exception e) {
      10. e.printStackTrace();
      11. }

    结果输出:

      1. before: 1
      2. after: 2

    可是若是咱们的成员变量是final呢?

      1. class Entity {
      2. public final int i = 1;
      3. }

    咱们再用上面的方式来进行修改值,发现出异常了:

    • java.lang.IllegalAccessException: Can not set final int field com.test.Entity.i to (int)2

    那咱们该怎么办呢?咱们能够修改为员变量的final修饰符,使其变为public int i = 1;具体方法以下:

      1. try {
      2. Entity e = new Entity();
      3. System.out.println("before: " + e.i);
      4. Field f = Entity.class.getDeclaredField("i");
      5. Field modifiersField = Field.class.getDeclaredField("modifiers");
      6. modifiersField.setAccessible(true);
      7.        
      8.        // 输出17:表示修饰符为:public final
      9.        System.out.println(f.getModifiers());
      10.        
      11.        /* 这里就是要修改修饰符了,至于为何是f.getModifiers() & ~Modifier.FINAL,你们看一下Modifier的源码就知道了*/
      12. modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
      13. // 输出1:表示修饰符已经被修改成:public
      14. System.out.println(f.getModifiers());
      15. f.setAccessible(true);
      16. f.setInt(e, 2);
      17. //f.set(e, 3);
      18. System.out.println("after: " + e.i);
      19. } catch (Exception e) {
      20. e.printStackTrace();
      21. }

    没有抛出异常了,可是确没有出现咱们想要的结果,输出为:

      1. before: 1
      2. 17
      3. 1
      4. after: 1

    这是为何呢?咱们稍微修改下Entity的代码以下:

      1. class Entity {
      2. public final Integer i = 1;
      3. }

    而后再执行,发现结果已经被修改了:

      1. before: 1
      2. 17
      3. 1
      4. after: 3

    说明我能够对对象数据类型进行修改,而不能对基本数据类型进行修改, 咱们再来试试String类型的:

      1. class Entity {
      2. public final String s = "a";
      3. }

      1. try {
      2. Entity e = new Entity();
      3. System.out.println("before: " + e.s);
      4. Field f = Entity.class.getDeclaredField("s");
      5. Field modifiersField = Field.class.getDeclaredField("modifiers");
      6. modifiersField.setAccessible(true);
      7. System.out.println(f.getModifiers());
      8. modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
      9. System.out.println(f.getModifiers());
      10. f.setAccessible(true);
      11. //f.setInt(e, 2);
      12. f.set(e, "b");
      13. System.out.println("after: " + e.s);
      14. } catch (Exception e) {
      15. e.printStackTrace();
      16. }

    结果输出:

      1. before: a
      2. 17
      3. 1
      4. after: a

    咦?居然木有改变?咱们再对Entity稍微改动下:

      1. class Entity {
      2. public final String s = new String("a");
      3. }

    结果输出:

      1. before: a
      2. 17
      3. 1
      4. after: b

    总结一下,对于final修改的成员变量,基本数据以及public final String s = "a";这种方式不可被修改

    而对于对象数据类型是能够突破final限制进行修改的。

  • 相关阅读:
    四道二分例题答案
    5.1 Apache Hive DML语句与函数使用
    深入剖析Buddy 内存管理机制(上)
    1010 Radix 甲级 xp_xht123
    【冷启动#1】实用的MySQL基础
    高性能的5G毫米波天线(阵列)实现与性能评估
    网络安全70部学员第二阶段项目验收顺利结束
    深度解析单例模式
    BUUCTF【pwn】解题记录(4-6页持续更新中)
    【小程序】使用WXSS编写样式介绍以及与CSS的区别
  • 原文地址:https://blog.csdn.net/Andrew_Chenwq/article/details/125894418