Android 反射Field应用
2015-12-08 19:25
387 查看
面的几节涉及反射的一些基本概念,下面介绍在以后开发是经常需要的用到的一些反射技术使用.
由于在前面没有特别指出来,如何反射一个类,并且得到一个类的实例,所以在这里,首先列出一个我们经常在网上面见到的方式:
public static void getReflectionFields(ReflectionTest r) {
Class temp = r.getClass();
String className = temp.getName();
/**获取public的成员变量*/
Field[] fields = temp.getFields();
/**获取所有成员变量*/
Field[] dfields = temp.getDeclaredFields();
// printFields(fields ,temp ,r);
printFields(dfields, temp ,r);
}
说明:ReflectionTest是自定义的一个类,然后通过 Class temp = r.getClass();获取类的一个对象.接下来就是去获取类里面的变量,方法.为什么需要特别列出这么一段呢?如果从实际的开发角度出发,既然是要使用反射,怎么可能有ReflectionTest这种”显示”的类提供呢?我们想到反射的时候,一般或者说更多是去反射别人的类,而不是自己工程里面的类,这个类可能作为系统的类,也可能只是放在某个文件夹下.所以这里我建议这样:
这样做的好处是,我只需要传递一个packagename 给这个方法就好了,至于这个包名可以是自己工程里面的,也可以是系统里面的,也可以是放在某个文件夹中的.
注意到上面的区别以后,正式开始看一下,通过反射类,如何得到类里面的参数(Field),下面新建一个java工程,目录如下:
<1> : 首先新建一个被用于反射的类FlexClass.java:
/**
*
*/
package com.oneplus.flex;
/**
* @author zhibao.liu
* @Date 2015/11/18
* @company oneplus.Inc
*/
public class FlexClass {
private int Var1;
private String Var2;
private int Var3=12354;
private String Var4="hello , this is Var4 !";
private char Var5='B';
}
<2> : 由于这里面只涉及到Field的反射,所以类里面不再增加其他方法等.关于Field具体的API这里面不过去讲解(可以参考Field.java源代码),下面给出下面例子当中用到的:
[感觉上面表格变形了,不过最好点击下面的文档链接阅读更新的内容]
其余以此类推.
由于开篇的时候已经说了如何得到类的实例,下面我们获取类里面是参数变量,程序如下:
然后将上面放到:
运行结果:
大家需要注意的是:
<1> : field.setAccessible(true);设置这个可以保证将类中的private成员变量也反射出来,建议无论类中是否有私有还是无私有,均加上,当然如果读者能够时刻分的清楚,可以规规矩矩,是反射私有的时候才设置为true;
<2> : 如果反射的类里面的变量没有赋初值,像int型,系统会给一个默认值0,但是String就不会,所以在得到String类型的时候,一定要判断返回值是否为NULL,当然这并不是说其他的基本类型就不需要判断的,只是String等类型不判断,直接会导致程序异常!
上面只是介绍获取参数的基本信息,如名字,数据类型等,下面继续举例如何获取变量值,程序如下,以获取Char Var5为例 :
private static void GetCharFlexFieldClass(String packagename,String fieldname){
try {
Class clazz=Class.forName(packagename);
try {
Object obj=clazz.newInstance();
try {
// 获取制定字段名的对象
Field field=clazz.getDeclaredField(fieldname);
field.setAccessible(true);
//注意下面,使用的是getChar(Object object)方式
//对于其他类型,以此类推,如getInt(Object object)
Object vobj=field.getChar(obj);
if(vobj!=null){
System.out.println("Field Char : "+vobj.toString());
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
注意 : 程序Field类提供了比如getChar(Object object),getInt(Object object)等方法,用于获取制定类型的值,也提供get(Object object)
方法,当如果你的反射类中包含另外一些自定义的类变量时,可以使用这个方法去获取.
好了,虽然上面是以获取Char型,但是可以举一反三,在这一节的后面,我尽量提供其他一些实例参考作为补充.
下面接下来是修改读取出来的Field参数值.在做之前,我们可以做一次联想,java等高级语言往往有成对的方法接口,有getChar(Object object),就意味着有setChar(Object object, Object object),看看下面设置参数值,程序如下:
程序很简单,运行结果:
结果变成了字符H.
看了上面,很多读者会问,上面就是简简单单的java语言使用而已,和Android没什么关系,也没看见如何在Android使用,那么下面通过一个实例来看一看在Android是如何使用的:
<1> : 新建一个Android 工程,目录如下:
<2>: 布局如下 :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".OneplusFlexFieldActivity" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/button"
android:text="@string/oneplus_button"/>
</RelativeLayout>
Value目录下如下:
增加一个oneplus_string的文件,内容如下 :
<3> : 主类程序如下 :
运行结果 :
下面在给出获取制定参数的值 :
在主工程里面增加一个按钮,在按钮点击事件中调用:
运行结果 :
根据上面的方式,同样可以获取Android里面很多其他类型的资源ID,从而可以调用Android系统各种系统资源,正如上面的,既然可以获取,那么同样也可以设置某些参数的值,的确是这样的,同样可以设置,但是Android系统的这些参数值用Set…可是搞不定的,这里暂时不介绍!
附录 :
下面贴出一些其他供参考的测试代码,这些代码可以在我提供的demo程序中找到:
由于在前面没有特别指出来,如何反射一个类,并且得到一个类的实例,所以在这里,首先列出一个我们经常在网上面见到的方式:
public static void getReflectionFields(ReflectionTest r) {
Class temp = r.getClass();
String className = temp.getName();
/**获取public的成员变量*/
Field[] fields = temp.getFields();
/**获取所有成员变量*/
Field[] dfields = temp.getDeclaredFields();
// printFields(fields ,temp ,r);
printFields(dfields, temp ,r);
}
说明:ReflectionTest是自定义的一个类,然后通过 Class temp = r.getClass();获取类的一个对象.接下来就是去获取类里面的变量,方法.为什么需要特别列出这么一段呢?如果从实际的开发角度出发,既然是要使用反射,怎么可能有ReflectionTest这种”显示”的类提供呢?我们想到反射的时候,一般或者说更多是去反射别人的类,而不是自己工程里面的类,这个类可能作为系统的类,也可能只是放在某个文件夹下.所以这里我建议这样:
private static void FlexClass(String packagename){ try { Class clazz=Class.forName(packagename); try { Object obj=clazz.newInstance(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
这样做的好处是,我只需要传递一个packagename 给这个方法就好了,至于这个包名可以是自己工程里面的,也可以是系统里面的,也可以是放在某个文件夹中的.
注意到上面的区别以后,正式开始看一下,通过反射类,如何得到类里面的参数(Field),下面新建一个java工程,目录如下:
<1> : 首先新建一个被用于反射的类FlexClass.java:
/**
*
*/
package com.oneplus.flex;
/**
* @author zhibao.liu
* @Date 2015/11/18
* @company oneplus.Inc
*/
public class FlexClass {
private int Var1;
private String Var2;
private int Var3=12354;
private String Var4="hello , this is Var4 !";
private char Var5='B';
}
<2> : 由于这里面只涉及到Field的反射,所以类里面不再增加其他方法等.关于Field具体的API这里面不过去讲解(可以参考Field.java源代码),下面给出下面例子当中用到的:
getChar(Object obj) | |
getInt(Object obj) | |
getName() | |
getType() | |
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html |
其余以此类推.
由于开篇的时候已经说了如何得到类的实例,下面我们获取类里面是参数变量,程序如下:
private static void FlexFieldClass() { try { Class clazz = Class.forName("com.oneplus.flex.FlexClass"); try { Object obj = clazz.newInstance(); //获取类中所有Field Field[] fields = clazz.getDeclaredFields(); //下面循环获取所有类的名字,数据类型,以及对应值 for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); System.out.println("Field " + i + " name : " + fields[i].getName() + " Type : " + fields[i].getType()); try { Field field = clazz.getDeclaredField(fields[i] .getName()); field.setAccessible(true); //获取对应的值 Object vobj = field.get(obj); if (vobj != null) { System.out.println("Field " + i + " name : " + vobj.toString()); } else { System.out.println("Field " + i + " name : NULL"); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
然后将上面放到:
public static void main(String[] args) { // TODO Auto-generated method stub FlexFieldClass(); }
运行结果:
大家需要注意的是:
<1> : field.setAccessible(true);设置这个可以保证将类中的private成员变量也反射出来,建议无论类中是否有私有还是无私有,均加上,当然如果读者能够时刻分的清楚,可以规规矩矩,是反射私有的时候才设置为true;
<2> : 如果反射的类里面的变量没有赋初值,像int型,系统会给一个默认值0,但是String就不会,所以在得到String类型的时候,一定要判断返回值是否为NULL,当然这并不是说其他的基本类型就不需要判断的,只是String等类型不判断,直接会导致程序异常!
上面只是介绍获取参数的基本信息,如名字,数据类型等,下面继续举例如何获取变量值,程序如下,以获取Char Var5为例 :
private static void GetCharFlexFieldClass(String packagename,String fieldname){
try {
Class clazz=Class.forName(packagename);
try {
Object obj=clazz.newInstance();
try {
// 获取制定字段名的对象
Field field=clazz.getDeclaredField(fieldname);
field.setAccessible(true);
//注意下面,使用的是getChar(Object object)方式
//对于其他类型,以此类推,如getInt(Object object)
Object vobj=field.getChar(obj);
if(vobj!=null){
System.out.println("Field Char : "+vobj.toString());
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
注意 : 程序Field类提供了比如getChar(Object object),getInt(Object object)等方法,用于获取制定类型的值,也提供get(Object object)
方法,当如果你的反射类中包含另外一些自定义的类变量时,可以使用这个方法去获取.
好了,虽然上面是以获取Char型,但是可以举一反三,在这一节的后面,我尽量提供其他一些实例参考作为补充.
下面接下来是修改读取出来的Field参数值.在做之前,我们可以做一次联想,java等高级语言往往有成对的方法接口,有getChar(Object object),就意味着有setChar(Object object, Object object),看看下面设置参数值,程序如下:
private static void SetCharFlexFieldClass(String packagename,String fieldname){ try { Class clazz=Class.forName(packagename); try { Object obj=clazz.newInstance(); try { Field field=clazz.getDeclaredField(fieldname); field.setAccessible(true); // 设置一个Char 字符进去 field.setChar(obj, 'H'); //然后再获取出来 Object vobj=field.getChar(obj); //获取出来以后,再打印出来 if(vobj!=null){ System.out.println("Modified Field Char : "+vobj.toString()); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
程序很简单,运行结果:
结果变成了字符H.
看了上面,很多读者会问,上面就是简简单单的java语言使用而已,和Android没什么关系,也没看见如何在Android使用,那么下面通过一个实例来看一看在Android是如何使用的:
<1> : 新建一个Android 工程,目录如下:
<2>: 布局如下 :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".OneplusFlexFieldActivity" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/button"
android:text="@string/oneplus_button"/>
</RelativeLayout>
Value目录下如下:
增加一个oneplus_string的文件,内容如下 :
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="oneplus_button">button</string> </resources>
<3> : 主类程序如下 :
package com.oneplus.oneplusandroidflexfield; import java.lang.reflect.Field; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class OneplusFlexFieldActivity extends Activity implements OnClickListener { private final static String TAG="OneplusFlexFieldActivity"; private final static String ONEPLUS_ANDROID_RESOURCE = "com.android.internal.R$dimen"; private Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.oneplus_flex_field); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(this); } @Override public void onClick(View arg0) { // TODO Auto-generated method stub int resId = arg0.getId(); switch (resId) { case R.id.button: OneplusFlexAndroidResource(OneplusFlexFieldActivity.this,ONEPLUS_ANDROID_RESOURCE); break; default: } } private void OneplusFlexAndroidResource(Context context, String packagename) { try { Class clazz = Class.forName(packagename); try { Object obj = clazz.newInstance(); Field fields[] = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { try { Field field = clazz.getDeclaredField(fields[i].getName()); field.setAccessible(true); Object vobj = field.get(obj); if (vobj != null) { //下面是获取到了android系统的资源ID了 int resID = Integer.parseInt(vobj.toString()); Object ret = context.getResources().getDimension(resID); Log.i(TAG,"Field Name : " + field.getName() + " Field Resource Value : " + ret.toString()); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
运行结果 :
下面在给出获取制定参数的值 :
private void OneplusFlexAndroidResource(Context context, String packagename, String fieldname) { try { Class clazz = Class.forName(packagename); try { Object obj = clazz.newInstance(); try { Field field = clazz.getDeclaredField(fieldname); field.setAccessible(true); Object ret = field.get(obj); int resID = Integer.parseInt(ret.toString()); Object vret = context.getResources().getDimension(resID); Log.i(TAG, "vret : " + vret.toString()); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
在主工程里面增加一个按钮,在按钮点击事件中调用:
OneplusFlexAndroidResource(OneplusFlexFieldActivity.this, ONEPLUS_ANDROID_RESOURCE, "status_bar_height");
运行结果 :
根据上面的方式,同样可以获取Android里面很多其他类型的资源ID,从而可以调用Android系统各种系统资源,正如上面的,既然可以获取,那么同样也可以设置某些参数的值,的确是这样的,同样可以设置,但是Android系统的这些参数值用Set…可是搞不定的,这里暂时不介绍!
附录 :
下面贴出一些其他供参考的测试代码,这些代码可以在我提供的demo程序中找到:
private static void GetFlexFieldClass(String packagename, String fieldname) { try { Class clazz=Class.forName(packagename); try { Object obj=clazz.newInstance(); try { Field field=clazz.getDeclaredField(fieldname); field.setAccessible(true); Object vobj=field.get(obj); if(vobj!=null){ System.out.println("Field Name : "+field.getName()+" Field Type : "+field.getType()+" Field Value : " + vobj.toString()); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static void SetFlexFieldClass(String packagename, String fieldname) { try { Class clazz = Class.forName(packagename); try { Object obj = clazz.newInstance(); try { Field field = clazz.getDeclaredField(fieldname); field.setAccessible(true); Object vobj = field.get(obj); if (vobj != null) { System.out.println("before read field value : " + vobj.toString()); } // make String as example followly field.set(obj, "oneplus zhibao.liu"); // read it again after modify vobj = field.get(obj); if (vobj != null) { System.out.println("after read field value : " + vobj.toString()); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
相关文章推荐
- Android No Launcher activity found!
- Android 获取手机总内存和可用内存等信息
- android Widget添加过程和android添加widget不更新的问题分析解决
- Android多屏幕自适应解决方案
- android 旋转屏幕导致Activity重建解决方法
- android adb 卸载内置系统apk方法
- Android 操作SQLite基本用法
- android greenDao SQLite数据库操作使用的工具
- android中的Activity的开启StartActivity()和StartActivityForResult()
- Edittext弹出键盘移动屏幕底部Button的实现
- Android的HelloWorld
- Android AutoLayout全新的适配方式 堪称适配终结者
- android项目获得手机里所有的应用程序
- android反编译工具
- popupwindow全屏幕显示被状态栏挡住如何解决+Android获取状态栏高度
- Android-socket服务端断重启后,android客户端自动重连
- Mac下Android Studio中获取SHA1和MD5
- Android 图片平铺实现方式
- android studio导入 so ,jar 文件。
- Android Adapter记住CheckBox状态