可否經過反射修改被 final 修飾的成員變量?

1、背景

平常磨刀優化

2、閱前須知知識點:

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

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

一、不能被修改的狀況,直接貼代碼講this

//建立一個實體類
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

解釋:

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

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

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

public class Demo
{
  private final int info = 123;

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

二、能被修改的狀況編譯

//建立一個實體類
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

解釋:

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

二、定義的時候並無初始化值,getInfo方法返回的是info這個變量test

如下Demo 類反編譯的代碼變量

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

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

4、總結

因此成員變量在定義的時候沒有初始化值的時候,就算用final修飾,同樣能夠被經過反射以後進行修改權限

相關文章
相關標籤/搜索