Android 反射枚举Enum类型应用

本文详细介绍了如何在Java中通过反射处理枚举类型,特别是在Android环境中。作者通过一个测试程序展示了如何获取枚举类型的Class对象,以及在方法中传递枚举类型参数时的处理方式,强调了在反射未知枚举类时,可以将其视为内部类进行处理。文中还讨论了在处理不同路径下的jar包时,使用ClassLoader的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上关于反射枚举的案例似乎不多,也许是因为枚举在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方法成功.































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值