反射,是将类的组成部分拆解为更小的类,以便更好的调用和操作这个类本身,大概可以理解为把一个类(Class)的
- 构造方法,封装为 Constructor 类
- 成员属性,封装为 File 类
- 成员方法,封装为 Method 类
反射,为java提供了类的灵活调度(动态调用类的属性、方法、构造),现在的框架都基于反射和注解。
获取Class对象
这里的Class,指的是java.lang.Class<T>,参考文档java.lang.Class
每一个运行中的对象,都会自动对应一个class对象。有3种方法获取Class对象,三种获取的是同一个对象
//1.第一种,把类加载进内存,并返回Class对象,多用于加载配置文件
Class.forName("全限定类名"); //即包名.类名
//2.通过类名的属性获取,多用于参数传递
类名.class
//3.通过对象的方法getClass获取,多用于对象获取字节码
对象.getClass();
注意, 反射使用时都必须使用Class对象,没有Class对象也就无法进行后续操作。
Class对象的功能
1.获取类名
// my是一个Class对象
my.getName(); //这个类名,是全限定类名,即包名.类名
my.getSimpleName();//仅类名
2.获取成员变量 Field 对象 (java.lang.reflect.Field)
Class myClass = My.Class; //先获取一个 Class
Filed[] fields = myClass.getFields(); //获取所有的public成员变量
for(Field field : fields){
System.out.println(field);
}
Field a = myClass.getField("a"); //获取一个public成员变量,变量名为a
//如果需要对取变量值,或设置值,只能设置某个对象
My my = new My();
Object value = a.get(my);//取值
a.set(my,"张三"); //设置值
//如果需要获取所有成员变量,getDeclareFields();
//所有变量种获取一个指定的成员变量,getDeclareField("变量名");
//对于私有变量,可以使用 field.setAccessible(true); 也叫暴力反射
3.获取构造器 Constructor 对象(java.lang.reflect.Constructor)
//获取一个构造器对象,如果有参数,需要传递参数类型的class,Constructors不讲
Constructor constructor = myClass.getConstructor(String.class,int.class);
//使用构造器创建对象
Object myObject = constructor.newInstance("张三","23");
//对于私有的属性等,需要用getDeclareConstructor,以及暴力反射等
//对于无参构造,可以直接使用 Class.newInstance();
4.获取方法 Method 对象(java.lang.reflect.Method)
Method met = myClass.getMethod("myMethod"); //获取指定的方法,Methods不讲
//对于私有方法,类似有 getDeclareMethod,暴力反射等也不讲
//需要执行方法,必须 new 对象
met.invoke(my); //使用对象执行方法
//对于重载的方法,可以指定参数
Method met2 = myClass.getMethod("myMethod",String.class);
met2.invoke(my,"Java教程");
反射的基本使用
使用反射,取私有属性,调用方法,获取构造方法等
package abc; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.Scanner; public class Person { private char sex = '男'; public String name = "张三"; private int age; public Person(){ } public Person(int age){ this.age = age; } public int getAge() { System.out.println(this.age); return age; } public void setAge(int age) { this.age = age; } public static void main(String[] args) throws Exception { Person p = new Person(); // 1.取出p对象的私有属性sex的值 char sex = (Character)p.getClass().getDeclaredField("sex").get(p); System.out.println(sex); // 2.从控制台输入一个名称,并根据名称调用p对象中对应的方法 String method_name = new Scanner(System.in).next(); p.getClass().getMethod(method_name).invoke(p); // 3.获取所有的构造方法 Constructor<?>[] constructors = p.getClass().getConstructors(); System.out.println(Arrays.toString(constructors)); // 4.控制台输入一个类名,根据该类名创建对象... } }
程序执行结果:
- 男
- getAge
- 0
- [public abc.Person(), public abc.Person(int)]
你可以看到,反射非常灵活,但注意不要过度使用,它会降低安全性、降低性能、并使维护变得困难。
封装工具类实例
反射可以很灵活的封装各种工具,例如以下实例
把Object转换为Map
/**
* 把Object转换为Map
* @param object 需要转换的Object
* @return 对应Object转换后的Map
*/
public static Map<String,Object> getFromObject(Object object){
Map<String,Object> map = new HashMap<>();
for (Field field : object.getClass().getDeclaredFields()) {
try{
boolean oldAccess = field.isAccessible();
field.setAccessible(true);
map.put(field.getName(),field.get(object));
field.setAccessible(oldAccess);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return map;
}
把Map转换为Object
/**
* 把map转换为实体类
* @param map 需要转换的map
* @param entity 目标实体类
* @param <T> 实体类的泛型
* @return 转换后的Object
*/
public static <T> T toEntity(Map<String,Object>map, Class<T> entity){
T t = null;
try{
t = entity.newInstance();
for (Field field : entity.getDeclaredFields()) {
if(map.containsKey(field.getName())){
boolean oldAccess = field.isAccessible();
field.setAccessible(true);
Object object = map.get(field.getName());
if(object!=null){
String type = field.getType().toString();
//把java.math.BigDecimal兼容为int
if(type.equals("int")){
String sInt = object.toString();
field.set(t,Integer.parseInt(sInt));
}
//把java.sql.Timestamp兼容为java.sql.Date
else if(type.equals("class java.sql.Date") && object.getClass().toString().equals("class java.sql.Timestamp")){
Timestamp time = (Timestamp)object;
Date date = new Date(time.getTime());
field.set(t,date);
}
//判断格式是否兼容,否则为null
else if(field.getType().isAssignableFrom(object.getClass())){
field.set(t,object);
}
}
field.setAccessible(oldAccess);
}
}
}catch (Exception e){
e.printStackTrace();
}
return t;
}
本篇完,还有疑问?留下评论吧