当前位置: 首页 > java>阅读正文

java反射的概念及基本使用

2021.10.28 朱丰华 85 次 留下评论 3863字

反射,是将类的组成部分拆解为更小的类,以便更好的调用和操作这个类本身,大概可以理解为把一个类(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;
    }

本篇完,还有疑问?留下评论吧

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注