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的形式处理.这种情况可以使用jar在android系统路径下,这个路径下不是指目录路径下,而是特指引用路径下,即可以直接被用户引用的路径下.如果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方法成功.
- Android 反射枚举Enum类型应用
- Enum(枚举类型)的应用
- Enum(枚举类型)的基本应用
- Android enum(枚举类型)使用详解
- Android枚举类型(enum)替换方案
- Java enum 枚举类型
- C#枚举类型enum
- C#枚举类型enum
- C#枚举类型enum
- enum枚举类型学习
- JAVA枚举类型Enum
- 枚举类型-enum使用
- C枚举类型enum
- C枚举类型enum
- 枚举类型------enum
- Enum 枚举类型
- [Java] enum 枚举类型
- Java enum 枚举类型
- 交叉工具链
- canvas画布
- poj 1321棋盘问题(搜索)
- 深度学习之门------网址汇总
- POJ3249 Test for Job(拓扑排序+dp)
- Android 反射枚举Enum类型应用
- 概率题 阿里
- UIImage的属性整理
- 大数据时代:生活、工作与思维的大变革(下)
- POJ 1753 (高斯消元)
- Mac平台重新设置MySQL的root密码
- 大话设计模式_中介模式c++实现
- http_cracker.sh
- print float as int 的分析