java 反射

Class 类

java 运行时系统始终为所有对象维护一个运行时类型标识,这个信息就是类的说明书,会 跟踪每一个对象所属的类。保存这些信息的类名为 Class。

获取某个类的 Class 类对象:

// getClass 方法返回类名对应的Class对象
Employee e = new Employee();
Class cl = e.getClass();

// 使用静态方法forName获得类名对应的Class对象
String className = "java.util.Random";
Class cl = Class.forName(className);

// 如果T是任意的java类,T.class 将是匹配的类对象
Class cl1 = Random.class;
Class cl2 = int.class;
Class cl3 = Double[].class;

Class 类也是一个泛型类:Emplyee.class 的类型是 Class

使用 Class 类查找获取资源的功能

  • 什么是资源文件:一般指除了.java 和.class 结尾的文件,都是资源文件,例如图像和 声音文件。

在一个拥有资源文件的类的 Class 对象 ResourceTest 中

Class cl = ResourceTest.class;
URL aboutURL = cl.getResource("about.gif");
var icon = new ImageIcon(aboutURL);

InputStream stream = cl.getResourceAsStream("data/about.txt");
var about = new String(stream.readAllBytes(),"UTF-8");
  • 一个实例

public class MapBeanConverter {
    // 传入一个遵守Java Bean约定的对象,读取它的所有属性,存储成为一个Map
    // 例如,对于一个DemoJavaBean对象 { id = 1, name = "ABC" }
    // 提示:
    //  1. 读取传入参数bean的Class
    //  2. 通过反射获得它包含的所有名为getXXX/isXXX,且无参数的方法(即getter方法)
    //  3. 通过反射调用这些方法并将获得的值存储到Map中返回
    public static Map<String, Object> beanToMap(Object bean) {
        Map<String, Object> map = new HashMap<>();
        Class beanClass = bean.getClass();
        Method[] methods = beanClass.getDeclaredMethods();
        for (Method method :
                methods) {
            String methodName = method.getName();
            Boolean isStartWithGetorIs = methodName.startsWith("get") || methodName.startsWith("is");
            int methodParameterNumber = method.getParameterTypes().length;
            if (methodParameterNumber == 0 && isStartWithGetorIs) {
                try {
                    Object obj = beanClass.getMethod(methodName).invoke(bean);
                    map.put(methodName, obj);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return map;
    }

    // 传入一个遵守Java Bean约定的Class和一个Map,生成一个该对象的实例
    // 传入参数DemoJavaBean.class和Map { id -> 1, name -> "ABC"}
    // 应当返回一个DemoJavaBean对象 { id = 1, name = "ABC" }
    // 提示:
    //  1. 遍历map中的所有键值对,寻找klass中名为setXXX,且参数为对应值类型的方法(即setter方法)
    //  2. 使用反射创建klass对象的一个实例
    //  3. 使用反射调用setter方法对该实例的字段进行设值
    public static <T> T mapToBean(Class<T> klass, Map<String, Object> map) {
        try {
            Object klassInstance = klass.getConstructor().newInstance();
            for (String key :
                    map.keySet()) {
                Field declaredField = klass.getDeclaredField(key);
                declaredField.setAccessible(true);
                declaredField.set(klassInstance,map.get(key));
            }
            return (T) klassInstance;
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        DemoJavaBean bean = new DemoJavaBean();
        bean.setId(100);
        bean.setName("AAAAAAAAAAAAAAAAAAA");
        System.out.println(beanToMap(bean));

        Map<String, Object> map = new HashMap<>();
        map.put("id", 123);
        map.put("name", "ABCDEFG");
        System.out.println(mapToBean(DemoJavaBean.class, map));
    }

    public static class DemoJavaBean {
        private Integer id;
        private String name;
        private String privateField = "privateField";

        public int isolate() {
            System.out.println(privateField);
            return 0;
        }

        public String is() {
            return "";
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public String getName(int i) {
            return name + i;
        }

        public void setName(String name) {
            this.name = name;
        }

        public boolean isLongName() {
            return name.length() > 10;
        }

        @Override
        public String toString() {
            return "DemoJavaBean{"
                    + "id="
                    + id
                    + ", name='"
                    + name
                    + '\''
                    + ", longName="
                    + isLongName()
                    + '}';
        }
    }
}

Last updated

Was this helpful?