Android 枚举与反射
一、知识积累
1、反射
(1)反射机制
加载完类之后,会产生一个Class类型的对象,可通过此对象看到类的结构,这就是反射,反射机制允许程序在执行期间使用ReflectionAPI取得类的内部消息,并能够直接操作对象的内部属性及方法。
(2)常用方法
方法名 | 作用 |
---|---|
forName(String name) | 根据name获取Class对象(ps:name为类的全类名) |
class.getName() | 获取Class对象表示的实体名称 |
getFields()/getField(String name) | 获取所有公开的成员变量(ps:包括继承变量)/根据name获取Class对象的成员变量(ps:包括继承变量) |
getDeclaredFields()/getDeclaredField(String name) | 获取Class对象定义的成员变量(ps:包括 私有成员变量)/根据name获取Class对象的成员变量 |
getMethods()/getDeclaredMethods() | 获取Class对象所有可见方法(ps:包括继承方法)/获取Class对象定义的方法(ps:包括私有,不包括继承方法) |
getMethod(String methodfName, parameter list)/getDeclaredMethod(String methodName, parameter list) | 根据方法名和参数类型列表获取到Class对象对应的方法(ps:包括继承)/根据方法名和参数类型列表获取到Class对象对应的方法(包括私有,不包括继承方法) |
class.newInstance()/clazz.newInstance() | 通过无参和有参构造对象 |
2、枚举
(1)枚举
枚举是一组有限的常量集合。
(2)常用方法
方法名 | 作用 |
---|---|
name() | 返回当前对象名 |
ordinal() | 返回当前对象的索引 |
values() | 返回枚举类中的所有常量对象 |
valueOf(String name) | 根据name转换成已存在的枚举对象 |
compareTo() | 比较两个枚举常量的大小 |
(3)注意
值得一提的是,java的枚举和C++中的枚举不一样,当我尝试使用values方法获取一下枚举的枚举值时,与预期结果不一样,C++中的枚举,实际上是整型常数的有限集合。C++编译会根据定义的顺序自动赋值为0,1,2,3…在java枚举中使用values()打印所有值,会出现一下结果:
enum Week{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
这是因为Week中的Sunday、Monday…Saturday均表示一个枚举对象,等同于:
enum Week{
public static final Week Sunday = new Week();
public static final Week Monday= new Week();
public static final Week Tuesday= new Week();
public static final Week Wednesday= new Week();
public static final Week Thursday= new Week();
public static final Week Friday= new Week();
public static final Week Saturday= new Week();
}
values()方法的实现为:
public static Week values(){
return (Week[]) $VALUES.clone();
}
//$VALUES为所有枚举常量
Week[] $VALUES = new Week[7];
$VALUES[0] = Sunday;
$VALUES[1] = Monday;
$VALUES[2] = Tuesday;
$VALUES[3] = Wednesday;
$VALUES[4] = Thursday;
$VALUES[5] = Friday;
$VALUES[6] = Saturday;
二、实现
具体流程如下:
WeekTest.java
package com.test.enumdemo;
import android.util.Log;
/**
* @Author yang
* @Date 2023/2/6
*/
public class WeekTest {
enum Week{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
public void setWeek(Week week){
Log.d("dddddddddd", "setWeek: index="+week.ordinal());
}
}
MainActivity.java
package com.test.enumdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
testEnum();
}
private void testEnum(){
try {
//注意forName参数的美元符号
//获取枚举的class
Class clazz = Class
.forName("com.test.enumdemo.WeekTest$Week");
Class<?> clazz1 = Class.forName("com.test.enumdemo.WeekTest");
//创建对象
Object obj = clazz1.newInstance();
//获取对应的枚举对象
Object[] enumConstants = clazz.getEnumConstants();
Method method = clazz1.getMethod("setWeek",clazz);
method.invoke(obj,enumConstants[1]);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
打印结果:
三、优化
上面的实现方法是先获取了所有枚举对象,根据索引去传入对应的枚举对象,我们还可以直接创建枚举对象,实现如下:
private void testEnum(){
try {
//注意forName参数的美元符号
//获取枚举的class
Class clazz = Class
.forName("com.test.enumdemo.WeekTest$Week");
Class<?> clazz1 = Class.forName("com.test.enumdemo.WeekTest");
//创建对象
Object obj = clazz1.newInstance();
//获取对应的枚举对象
Object param = Enum.valueOf(clazz,"Sunday");
Method method = clazz1.getMethod("setWeek",clazz);
method.invoke(obj,param);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
打印结果如下: