Android 反射枚举Enum类型应用
2015-12-08 19:59
459 查看
网上关于反射枚举的案例似乎不多,也许是因为枚举在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文件:
<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()方法中:
为什么还写了这个方法,是因为发现如果内部类或者枚举类型当做参数在方法中传递,如何获取其类型:如下
而通过反射方法时,第二个参数需要提供方法参数的类型,如下
*代表传递参数的类型,如果是整形,即int.class,那么如果是枚举类型呢,或者内部类呢?这种情况是真实遇见过的,所以才提别提出来,程序里面写了测试方法:
这个方法的参数需要传递一个枚举类型,那么getDeclaredMethod第二参数如何传递呢,在这个单独demo中,可能可以用EducationLevelEnum.class,那是因为EducationLevelEnum这个枚举类型在自己主类中,但是反射一般都不会反射自己工程中的类,一般都是反射别人的jar中的类,所以上面传递的方式根本不实际,网上很多demo都是这样操作的,让人感觉莫名其妙!
这里特别做了通用处理,其中还包括:
这里是通过包名形式获取,而不是通过主类名.class的形式处理.这种情况可以使用jar在android系统路径下,这个路径下不是指目录路径下,而是特指引用路径下,即可以直接被用户引用的路径下.如果jar是随意放在Android系统任意路径下,就需要ClassLoader这个神器来处理了.
程序里面获取枚举类型/内部类的类型如下:
先获取主类的clazz对象,然后通过这个clazz获取主类中包括的枚举类型/内部类,这个获取真的很神奇.参考:
[http://download.oracle.com/technetwork/java/javase/6/docs/zh/api/java/lang/Class.html#getDeclaredClasses%28%29],
居然和getDeclaredFields()异曲同工,
getDeclaredFields()获取类中所有声明的基本参数变量,而getDeclaredClasses()获取类中声明的枚举类型/内部类的参数变量.也正是这个方式一击即中获取枚举类型/内部类类型,即可以传入需要的方法中:
这里面其实也尝试过:
即将claze.getClass()作为第二个参数传入getDeclaredMethod中,始终不行,一直卡住!
解决了上面的难题,运行结果,点击第一个按钮:
打印上面信息,说明测试反射枚举类型成功!
再点击第二个按钮:
打印出hi, I am zhibao.liu from oneplus,Inc, you flex enum successfully !信息,说明程序执行insertNum insertNum方法成功.
今天还是靠公司同事提醒了一下,发现枚举类型具有类的一些特性,虽然后面的操作中证实,在反编译后,即使不知道是枚举也没关系,就当做内部类反射处理就好了,不过同事还是给了一个思路,还是非常感谢的.
当时反射接口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他们控制的定义(一)
- Android百度云推送实现消息推送
- Android编码规范
- Android 反射接口Interface应用
- Android 反射Construct应用
- Android SDK Android NDK Android Studio 官方下载地址
- android项目复杂的listview
- Android - HelloWorld的Layout内容
- Android 反射Method应用
- Android/Java回调函数其实很简单
- Android异步加载图像(含线程池,缓存方法)
- android 包命名不管你怎么命,千万不要用下面几个
- Android简单实用的交互动画库
- android读取应用签名信息
- 第一个Android用例
- Android使用SimpleAdapter
- Android使用SimpleAdapter
- Android 反射Field应用
- Android No Launcher activity found!
- Android 获取手机总内存和可用内存等信息