概述
最近在使用Android Studio時遇到使用getDeclaredFields獲取到$change成員的問題,代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Field[] fields = Demo.class.getDeclaredFields();
for(Field f : fields) {
Log.d(TAG, "fields : " + f.getName() + " isSynthetic:" + f.isSynthetic());
}
}
static class Demo {
int test = 0;
}
}
得到的fields結果如下
D/MainActivity: fields : test
D/MainActivity: fields : $change
D/MainActivity: fields : serialVersionUID
解決
1. $change
在Google上搜索發現有人也遇到相同的問題
鏈接:Android Java objModelClass.getClass().getDeclaredFields() returns “$change” as one field
原因就是:Android Studio中有個Instant Run功能,如果開啓的話編譯器就會對所有類都添加$change成員變量。
2. serialVersionUID
serialVersionUID和Java的序列化機制有關。Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常,即是InvalidCastException。這裏猜測應該是AndroidStudio與Android手機安裝的應用程序進行序列化傳輸數據時用到的。
解決
解決方法有兩個:
1.關閉Android Studio的Instant Run功能
關掉後在運行一次試試:
D/MainActivity: fields : test
2.使用Field類中isSynthetic方法過濾掉編譯器自動生成的成員變量。
看一下isSynthetic方法的說明文檔:
boolean isSynthetic()
Returns true if this member was introduced by the compiler; returns false otherwise.
Returns:
true if and only if this member was introduced by the compiler.
Since:
1.5
如果是編譯器自動生成的Field的話isSynthetic會返回true,否則返回false。
雖然$change返回了true,但serialVersionUID返回的是false,所以這種方法並不好使。
D/MainActivity: fields : test isSynthetic:false
D/MainActivity: fields : $change isSynthetic:true
D/MainActivity: fields : serialVersionUID isSynthetic:false
3. 使用判斷語句過濾掉
for(Field f : fields) {
if(!(("$change".equals(f.getName()))||("serialVersionUID".equals(f.getName())))){
Log.d(TAG, "fields : " + f.getName() + " isSynthetic:" + f.isSynthetic());
}
}
再運行:
D/MainActivity: fields : test isSynthetic:false
綜述:建議選擇第一種或第三種解決辦法