Android 反射Field应用

来源:互联网 发布:php 找不到指定的模块 编辑:程序博客网 时间:2024/05/16 04:46

面的几节涉及反射的一些基本概念,下面介绍在以后开发是经常需要的用到的一些反射技术使用.

由于在前面没有特别指出来,如何反射一个类,并且得到一个类的实例,所以在这里,首先列出一个我们经常在网上面见到的方式:

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 blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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();//获取类中所有FieldField[] 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 blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}

然后将上面放到:

public static void main(String[] args) {// TODO Auto-generated method stubFlexFieldClass();}

运行结果:



大家需要注意的是:

<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 blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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 implementsOnClickListener {private final static String TAG="OneplusFlexFieldActivity";private final static String ONEPLUS_ANDROID_RESOURCE = "com.android.internal.R$dimen";private Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.oneplus_flex_field);mButton = (Button) findViewById(R.id.button);mButton.setOnClickListener(this);}@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubint 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 blocke.printStackTrace();}}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.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 followlyfield.set(obj, "oneplus zhibao.liu");// read it again after modifyvobj = field.get(obj);if (vobj != null) {System.out.println("after read field value : "+ vobj.toString());}} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}





































0 0
原创粉丝点击