Android 修改 final 類型的 field

這是一個比較特殊的知識點,需要從HotSpot與Dalvik的區別說起。

問題起因

相信大家在繼承RecycleView時,對ViewHolder中的itemView都有重寫的慾望。這個itemView是final類型的,不容許被修改,極大的限制了開發的自由。
那首先想到的就是利用反射來修改該字段。可是運行會報錯。

創建一個通用方法進行反射修改屬性值,如下:

public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
 Field field = object.getClass().getDeclaredField(fieldName);
 
 Field modifiersField = Field.class.getDeclaredField("modifiers");
 modifiersField.setAccessible(true); //Field 的 modifiers 是私有的
 modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
 
 if(!field.isAccessible()) {
  field.setAccessible(true);
 }
 
 field.set(object, newFieldValue);
}

在實際運行時,會報錯,提示說沒有modifiers字段。這也就表明,Android編譯後的dex字節碼中,並沒有java那一套複雜屬性訪問控制邏輯。

反射時忽視final修飾符

調整代碼,不管final,直接嘗試修改itemView

Field field =  RecyclerView.ViewHolder.class.getField("itemView");
field.set(viewHolder, someNewItemView);

此時是可以正常運行的。

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