Android 反射枚举Enum类型应用

来源:互联网 发布:蜘蛛网络源码 编辑:程序博客网 时间:2024/04/29 07:08

网上关于反射枚举的案例似乎不多,也许是因为枚举在java里面枚举类型其实算个准类了,java编译的时候同样会生成一个enumname.Class文件,同时Enum是可以被子类直接继承的,所以有时候在反编译的时候反过跟头,掉过阴沟,真的坐船翻船,坐车爆胎,走路都要被石头绊倒的郁闷.同样也是证明不懂java基本知识,后果很严重!!!

今天还是靠公司同事提醒了一下,发现枚举类型具有类的一些特性,虽然后面的操作中证实,在反编译后,即使不知道是枚举也没关系,就当做内部类反射处理就好了,不过同事还是给了一个思路,还是非常感谢的.

当时反射接口Interface的时候,没有特别注意一下内部类.

下面自己亲自做了一个测试程序以供参考:

<1> : 新建一个Android工程,工程树如下:



<2>: Android工程里面添加两个按钮,布局如下:

<LinearLayout 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:orientation="vertical">    <Button        android:id="@+id/flextestbutton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/oneplus_flextest" />    <Button        android:id="@+id/flexbutton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/oneplus_flexenum" /></LinearLayout>

<3> : 布局中用到的字符串在oneplus_string.xml,这个是新建的一个values文件:

<?xml version="1.0" encoding="utf-8"?><resources>        <string name="oneplus_flexenum">Flex Enum Using</string>    <string name="oneplus_flextest">Flext Enum Test</string>    </resources>

<4>: 主体程序如下:

package com.oneplus.enumtype;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import android.os.Bundle;import android.app.Activity;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;/** * @author zhibao.liu * @date 2015-12-3 * @company : oneplus.Inc */public class OneplusEnumActivity extends Activity implements OnClickListener {    private final static String TAG="oneplus";    private Button mFlexEnumButton;    private Button mFlexEnumTestButton;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.oneplus_enum);        mFlexEnumButton = (Button) findViewById(R.id.flexbutton);        mFlexEnumButton.setOnClickListener(this);        mFlexEnumTestButton = (Button) findViewById(R.id.flextestbutton);        mFlexEnumTestButton.setOnClickListener(this);    }    private void FlexEnum() {        Log.i(TAG,"FlexEnum test .. ...");        try {//注意forName参数的美元符号            Class clazz = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity$EducationLevelEnum");            Method[] methods = clazz.getDeclaredMethods();            for (int i = 0; i < methods.length; i++) {                Log.i(TAG,"method name : " + methods[i].getName());            }            Field[] fields = clazz.getDeclaredFields();            for (int i = 0; i < methods.length; i++) {                Log.i(TAG,"field name : " + fields[i].getName());            }        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    private void FlexInsertEnum() {        try {            Class clazz = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity");            Class claze = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity$EducationLevelEnum");            Class[] clzs = clazz.getDeclaredClasses();            for (int i = 0; i < clzs.length; i++) {                Log.i(TAG,"Class type : " + clzs.getClass().toString());            }            try {                //clzs[0] : 这里是因为这个主类里面只有一个"内部类"/枚举类                //如果主类里面有很多个内部,那也没有关,可以进一步判断内部类里面的Method和Field做进一步识别判断                Method method = clazz.getDeclaredMethod("insertNum",                        new Class[] { clzs[0] /* claze.getClass() *//*                                                                     * EducationLevelEnum                                                                     * .class                                                                     */});                method.setAccessible(true);                try {                    method.invoke(clazz.newInstance(), new Object[] { null });                } catch (IllegalArgumentException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (IllegalAccessException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (InvocationTargetException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (InstantiationException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            } catch (NoSuchMethodException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    public void insertNum(EducationLevelEnum e) {        Log.i(TAG,"hi, I am zhibao.liu from oneplus,Inc, you flex enum sucessfully !");    }    public enum EducationLevelEnum {        DEFAULT("0", "------", 0),        HIGHSCHOOLDIPLOMA("1", "High School Diploma", 100),        ASSOCIATEDEGREE("5", "Associate Degree", 150),        BACHELORSDEGREE("2", "Bachelors Degree", 200),        MASTERSDEGREE("3", "Masters Degree", 300),        DOCTORATE("4", "Doctorate", 400);        EducationLevelEnum(String code, String codeDesc, Integer priority) {            this.code = code;            this.codeDesc = codeDesc;            this.priority = priority;        }        private String code;        private String codeDesc;        EducationLevelEnum(String code, String codeDesc) {            this.code = code;            this.codeDesc = codeDesc;        }        private Integer priority;        public Integer getPriority() {            return priority;        }        public String getCode() {            return code;        }        public String getCodeDesc() {            return codeDesc;        }    }    @Override    public void onClick(View v) {        // TODO Auto-generated method stub        int resid = v.getId();        switch (resid) {        case R.id.flexbutton:            FlexInsertEnum();            break;        case R.id.flextestbutton:            FlexEnum();            break;        default:            break;        }    }}

程序分析如下:

这里没有把枚举放在单独的类中了,做了直接反射主类来获取枚举类型:

首先看FlexEnum()方法中:

Class clazz = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity$EducationLevelEnum");

由于开篇说了枚举类型是个准类,所以在获取包名”类名”时,和获取内部类的方式一样,在主类和内部类/内部枚举之间以美元符号”$”间隔就可以了.

 

然后看FlexInsertEnum()方法中:

为什么还写了这个方法,是因为发现如果内部类或者枚举类型当做参数在方法中传递,如何获取其类型:如下

Private void method(Enum<?>);

而通过反射方法时,第二个参数需要提供方法参数的类型,如下

Clazz.getDeclaredMethod(“method”,Class[]{*});

*代表传递参数的类型,如果是整形,即int.class,那么如果是枚举类型呢,或者内部类呢?这种情况是真实遇见过的,所以才提别提出来,程序里面写了测试方法:

public void insertNum(EducationLevelEnum e) {        Log.i(TAG,"hi, I am zhibao.liu from oneplus,Inc, you flex enum sucessfully !");    }

这个方法的参数需要传递一个枚举类型,那么getDeclaredMethod第二参数如何传递呢,在这个单独demo中,可能可以用EducationLevelEnum.class,那是因为EducationLevelEnum这个枚举类型在自己主类中,但是反射一般都不会反射自己工程中的类,一般都是反射别人的jar中的类,所以上面传递的方式根本不实际,网上很多demo都是这样操作的,让人感觉莫名其妙!这里特别做了通用处理,其中还包括:

Class clazz = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity");

这里是通过包名形式获取,而不是通过主类名.class的形式处理.这种情况可以使用jarandroid系统路径下,这个路径下不是指目录路径下,而是特指引用路径下,即可以直接被用户引用的路径下.如果jar是随意放在Android系统任意路径下,就需要ClassLoader这个神器来处理了.

程序里面获取枚举类型/内部类的类型如下:

Class clazz = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity");            Class[] clzs = clazz.getDeclaredClasses();

先获取主类的clazz对象,然后通过这个clazz获取主类中包括的枚举类型/内部类,这个获取真的很神奇.参考:

[http://download.oracle.com/technetwork/java/javase/6/docs/zh/api/java/lang/Class.html#getDeclaredClasses%28%29], 居然和getDeclaredFields()异曲同工, getDeclaredFields()获取类中所有声明的基本参数变量,而getDeclaredClasses()获取类中声明的枚举类型/内部类的参数变量.也正是这个方式一击即中获取枚举类型/内部类类型,即可以传入需要的方法中:

Method method = clazz.getDeclaredMethod("insertNum",                        new Class[] { clzs[0] /* claze.getClass() *//*                                                                     * EducationLevelEnum                                                                     * .class                                                                     */});

这里面其实也尝试过:

Class claze = Class                    .forName("com.oneplus.enumtype.OneplusEnumActivity$EducationLevelEnum");

即将claze.getClass()作为第二个参数传入getDeclaredMethod,始终不行,一直卡住!

解决了上面的难题,运行结果,点击第一个按钮:

打印上面信息,说明测试反射枚举类型成功!

再点击第二个按钮:

打印出hi, I am zhibao.liu from oneplus,Inc, you flex enum successfully !信息,说明程序执行insertNum insertNum方法成功.































0 0