• java核心学习(三十九) 通过反射生成并操作对象


    一、创建对象

      通过反射创建对象有两种方式:

        1、 使用Class对象的newInstance()方法,这种方法实际上是使用默认的构造器起来创建该类的实例

        2、使用Class对象获取指定的Constructor对象,调用Constructor对象的newInstance()方法来获取来创建该Class的实例,这样可以根据参数类型来指定使用哪个构造器。

      下面代码实现一个简单工厂类,该工厂类可以根据配置文件产生Object类的子类

      

    public class ObjectFactory {
        private static String propertiesFileName;
        private static Map<String, Object> objectPool;
    
        public static String getPropertiesFileName() {
            return propertiesFileName;
        }
    
        public static void setPropertiesFileName(String propertiesFileName) {
            ObjectFactory.propertiesFileName = propertiesFileName;
        }
    
        public static Object getObject(String key) {
            if (objectPool.isEmpty()) {
                try (
                        FileInputStream fis = new FileInputStream(propertiesFileName)
                ) {
                    Properties props = new Properties();
                    props.load(fis);
                    for (String name : props.stringPropertyNames()) {
                        objectPool.put(name,CreatObject(props.getProperty(name)));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return objectPool.get(key);
        }
        public static Object CreatObject(String className)throws ClassNotFoundException,IllegalAccessException,InstantiationException{
            Class clazz = Class.forName(className);
            return clazz.newInstance();
        }
    }

    二、调用方法

      由Class对象可以获得该Class的Method对象,调用Method对象的invoke()方法可以调用该Method,下面为该方法签名:

          

       返回值Object即为执行方法后的返回值,第一个参数obj指定由哪个对象来执行该方法,后面的args参数代表执行该方法传入的参数。在调用invoke方法是要注意访问修饰符的权限。使用isAccessible方法来判断,使用setAccessible方法来判断权限。

      如果调用的方法为静态方法,则第一个参数为null。

       下面代码对上面的对象工厂加强,允许在配置文件中增加配置对象的的成员变量的值,对象工厂会读取配置并利用对象的setter方法设置成员变量的值。

       由于这个例子用作实验反射调用方法,所以另外实现了一个简单工厂类,而没有使用工厂模式将工厂类抽象出来便于拓展。

      

    public class ExtendObjectFactory {
        private static String propertiesFileName;
        private static Map<String, Object> objectPool;
    
        public static String getPropertiesFileName() {
            return propertiesFileName;
        }
    
        public static void setPropertiesFileName(String propertiesFileName) {
            ExtendObjectFactory.propertiesFileName = propertiesFileName;
        }
        public static Object CreatObject(String className)throws ClassNotFoundException,IllegalAccessException,InstantiationException{
            Class clazz = Class.forName(className);
            return clazz.newInstance();
        }
        public static Object getObject(String key){
            if (objectPool.isEmpty()) {
                try (
                        FileInputStream fis = new FileInputStream(propertiesFileName)
                ) {
                    Properties props = new Properties();
                    props.load(fis);
                    for (String name : props.stringPropertyNames()) {
    //                    objectPool.put(name,CreatObject(props.getProperty(name)));
                        //取出每一对key-value对,如果key中包含百分号,则认为该key用于控制对象的setter方法设置值,%前半为对象名字,后半控制setter方法名
                        if(name.contains("%")){
                            String[] objAndProp = name.split("%");
                            Object target = objectPool.get(objAndProp[0]);
                            String methodName = "set" + objAndProp[1].substring(0,1).toUpperCase()+objAndProp[1].substring(1);
                            Class targetClass = target.getClass();
                            Method setterMethod = targetClass.getMethod(methodName,String.class);
                            setterMethod.invoke(target,props.getProperty(name));
                        }else {
                            objectPool.put(name,CreatObject(props.getProperty(name)));
                        }
    
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return objectPool.get(key);
        }
    }

      配置文件的格式可以如同这般

    1 a=javax.swing.JFrame
    2 b=javax.swing.JLabel
    3 #set the title of a
    4 a%title=Test Title

    三、访问成员变量的值

      Field类提供了如下两组方法:

        getXxx(Object obj) :获取obj对象的的该成员变量的值,此处的Xxx指8种基本类型,若成员变量的类型为引用类型,则取消后面的Xxx。

        setXxx(Object obj,Xxx val) 类似于上面的方法。

    四、操作数组

      java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组,程序可以使用Array来动态创建数组,操作数组。

      Array类提供的方法签名:

      

      length参数是可变个数参数,有几个length参数就是几维数组,三维数组的元素是二维数组,二维数组的元素是一维数组。

    五、其他的操作不再一一演示,用的时候查阅文档即可

  • 相关阅读:
    springboot自动装配mybatisplus时,凭啥MybatisPlusAutoConfiguration比MybatisAutoConfiguration先装配
    mybatis 整合 spring 时,mapper 是怎么被设置必要的参数的
    canvas 画的线无法清除的问题
    大学英语单词 第二单元
    快乐纪中(二)2
    jzoj 2644. 数列
    jzoj【NOIP2011模拟10.31】T1游戏
    快乐纪中
    树形DP
    炮兵阵地
  • 原文地址:https://www.cnblogs.com/Theshy/p/7762232.html
Copyright © 2020-2023  润新知