假設咱們有以下一個類,咱們要利用反射來對其成員變量就行修改:java
class Entity { public int i = 1; }
通常咱們會這麼作:spa
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(); }
結果輸出:code
before: 1 after: 2
可是若是咱們的成員變量是final呢?
對象
class Entity { public final int i = 1; }
咱們再用上面的方式來進行修改值,發現出異常了:get
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的代碼以下:it
class Entity { public final Integer i = 1; }
而後再執行,發現結果已經被修改了:
io
before: 1 17 1 after: 3
說明我能夠對對象數據類型進行修改,而不能對基本數據類型進行修改class
咱們再來試試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
修改爲功,至於爲何會這樣,那得問java虛擬機了
好了,總結一下,對於final修改的成員變量,基本數據以及public final String s = "a";這種方式不可被修改
而對於對象數據類型是能夠突破final限制進行修改的,可是通常咱們也不多會這麼用