Java中有一个非常强大的技术:反射。通常我们可以使用反射技术去调用一个类的私有方法或者是访问和修改一个私有属性。
1. 如何获取一个类的类型
1.1 直接通过一个类的对象获取它的类型。
String reflect = "reflect";
Class clz = reflect.getClass();
1.2 通过类的命名空间和类名去获取类型
try {
// 获取EditText 类
Class clz = Class.forName("android.widget.EditText");
// 获取EditText的父类TextView
Class parentClz = clz.getSuperclass();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
1.3 直接通过类本身的class属性获取类型
Class clz = String.class;
1.4 TYPE属性,用于获取基本数据类型的类型
// 获取的类型为boolean
Class cla = Boolean.TYPE;
// 获取的类型为 java.lang.Boolean
Class clz = Boolean.class;
2 获取一个类的所有公有和私有的的方法和属性
2.1 获取构造函数
有这样一个类
public class ReflectClass {
public ReflectClass() {
System.out.println(ReflectClass.class.getSimpleName());
}
public ReflectClass(String a, Date date) {
System.out.println(ReflectClass.class.getSimpleName() + " " + a.getClass().getSimpleName() + date.getClass().getSimpleName());
}
private ReflectClass(String a) {
System.out.println(ReflectClass.class.getSimpleName() + " " + a.getClass().getSimpleName());
}
}
我们可以获取这个类的所有构造函数或者指定参数列表的构造函数
// 获取所有构造函数
Class clz = ReflectClass.class;
// 如果只想获取public构造函数使用 clz.getConstructors() 方法
for (Constructor constructor : clz.getDeclaredConstructors()) {
int mode = constructor.getModifiers();
System.out.println("修饰域 " + mode);
Class[] params = constructor.getParameterTypes();
if (params.length == 0) {
System.out.println("无参的构造函数");
} else {
for (Class cls : params) {
System.out.print(cls.getSimpleName() + " ");
}
System.out.println();
}
}
// 直接获取指定参数列表的构造函数
try {
Class[] param = {String.class};
Constructor constructor = clz.getDeclaredConstructor(param);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
2.2 调用构造函数生成对象
// 直接获取指定参数列表的构造函数
try {
Class[] param = {String.class};
Constructor constructor = clz.getDeclaredConstructor(param);
// 如果是私有构造函数,调用前一定要先调用这个方法
constructor.setAccessible(true);
constructor.newInstance("abc");
// 可以直接调用public无参构造函数
clz.newInstance();
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
2.3 访问和修改方法和字段
public class ReflectClass {
private int privateMemeber;
private int publicMemeber;
private static int staticMemeber;
public ReflectClass() {
System.out.println(ReflectClass.class.getSimpleName());
}
public ReflectClass(String a, Date date) {
System.out.println(ReflectClass.class.getSimpleName() + " " + a.getClass().getSimpleName() + date.getClass().getSimpleName());
}
private ReflectClass(String a) {
System.out.println(ReflectClass.class.getSimpleName() + " " + a.getClass().getSimpleName());
}
private void privateMethod() {
System.out.println("privateMethod is called");
}
public void publicMethod() {
System.out.println("publicMethod is called");
}
private static void staticMethod() {
System.out.println("staticMethod is called");
}
@Override
public String toString() {
return "ReflectClass{" +
"privateMemeber=" + privateMemeber +
", publicMemeber=" + publicMemeber +
", staticMemeber=" + staticMemeber +
'}';
}
}
try {
Class clz = ReflectClass.class;
Object obj = clz.newInstance();
// 获取所有的字段
for (Field field : clz.getDeclaredFields()) {
System.out.println("~~~~~~~~~~~获取字段~~~~~~~~");
System.out.println(field.toString());
// 非public字段在访问前一定要调用这个方法
field.setAccessible(true);
System.out.println(field.get(obj));
if (field.getType() == int.class) {
field.set(obj , 1);
} else if (field.getType() == boolean.class) {
field.set(obj,true);
} else if (field.getType() == String.class) {
field.set(obj,"hello world");
}
}
System.out.println("~~~~~~~~~~~获取字段结束~~~~~~~~");
System.out.println(obj.toString());
// 获取所有方法(不包括构造方法)
for (Method method : clz.getDeclaredMethods()) {
System.out.println("~~~~~~~~~~~方法~~~~~~~~");
System.out.println(method.toString());
method.setAccessible(true);
method.invoke(obj,null);
}
// 静态方法可以直接调用
Method method = clz.getDeclaredMethod("staticMethod",null);
method.setAccessible(true);
method.invoke(null,null);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}