能否通過反射修改被 final 修飾的成員變量? 原

一、背景

日常磨刀

二、閱前須知知識點:

  1. 當final修飾的成員變量在定義的時候初始化值,反射就不能動態修改它的值了。
  2. 當final修飾的成員變量在定義的時候沒有初始化值,就還能通過反射來動態修改它的值。
  3. 反射機制中的 setAccessible 代表的權限含義

三、舉例(這裏只用基本數據類型和包裝類來討論)

1、不能被修改的情況,直接貼代碼講

//創建一個實體類
public class Demo {
	private final int info = 123;

	public int getInfo() {
    	return info;
	}
}


//反射修改的代碼區域
public class TestFianl {
	public static void main(String[] args) {
		try {
			test();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public static void test() throws NoSuchFieldException, IllegalAccessException {
		Demo demo = new Demo();
		System.out.println("反射修改之前 Demo  實例的值:"+demo.getInfo());
		Field field = demo.getClass().getDeclaredField("info");
		field.setAccessible(true);//靈魂語句
		field.set(demo, 789);
		System.out.println("反射修改之後 Field 實例的值:"+field.get(demo));
		System.out.println("反射修改之後 Demo  實例的值:"+demo.getInfo());
	}
}
//輸出結果爲:
反射修改之前 Demo  實例的值:123
反射修改之後 Field 實例的值:789
反射修改之後 Demo  實例的值:123

解釋:

1、注意這裏的 修改的 成員變量 info 是被基本數據類型 int 修飾的

2、編譯的時候 被final修飾的成員變量會被優化,所有用到該變量的地方都被替換成了變量的內容 123

第二句話解釋看以下Demo 類反編譯的代碼

public class Demo
{
  private final int info = 123;

  public int getInfo() {
	return 123;//直接返回了 123 這個內容 而不是 info 這個變量
  }
}

2、能被修改的情況

//創建一個實體類
public class Demo {
	private final Integer info = 123;

	public Integer getInfo() {
		return info;
	}
}


//反射修改的代碼區域 和 1 中的沒有區別
public class TestFianl {
	public static void main(String[] args) {
		try {
			test();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public static void test() throws NoSuchFieldException, IllegalAccessException {
		Demo demo = new Demo();
		System.out.println("反射修改之前 Demo  實例的值:"+demo.getInfo());
		Field field = demo.getClass().getDeclaredField("info");
		field.setAccessible(true);//靈魂語句
		field.set(demo, 789);
		System.out.println("反射修改之後 Field 實例的值:"+field.get(demo));
		System.out.println("反射修改之後 Demo  實例的值:"+demo.getInfo());
	}
}
//輸出結果爲:
反射修改之前 Demo  實例的值:123
反射修改之後 Field 實例的值:789
反射修改之後 Demo  實例的值:789

解釋:

1、注意這裏的 修改的 成員變量 info 是被 包裝類 Integer 修飾的

2、定義的時候並沒有初始化值,getInfo方法返回的是info這個變量

以下Demo 類反編譯的代碼

public class Demo
{
  private final Integer info = Integer.valueOf(123);//定義的時候檢查再初始化了值

  public Integer getInfo() {
	return this.info;
  }
}

四、總結

所以成員變量在定義的時候沒有初始化值的時候,就算用final修飾,一樣可以被通過反射之後進行修改

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章