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参数就是几维数组,三维数组的元素是二维数组,二维数组的元素是一维数组。

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

原文地址:https://www.cnblogs.com/Theshy/p/7762232.html