概述
最近在使用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
综述:建议选择第一种或第三种解决办法