• 使用反射生成并操作对象


    一、获取Class对象的方式

    Java中,每个类被加载到内存中,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类,获得Class对象有三种方式:

    1.使用Class类的forName(String clazzName)静态方法,该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名。

    2.通过某个类的class属性获取,例如Person.class。

    3.调用某个对象的getClass()方法。该方法是java.lang.Object类中的一个方法,所以所有的Java对象都可以调用该方法,该方法将会返回该对象所属类对应的Class对象。

    对于第一种和第二种方法,都是直接根据类来取得该类的Class对象,相比之下,第二种方式有以下优势:

    代码更安全,程序在编译阶段就可以检查需要访问的Class对象是否存在。

    程序性能更好,因为这种方式无需调用方法。

    二、通过反射创建对象的方式

    有两种方式:

    1.使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法时实际上是利用默认构造器来创建该类的实例。

    2.先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例。

    三、调用方法

    当获得某个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或者指定方法。

    每个Method对象对应一个方法,获得Method对象后,程序就可通过该Method来调用它对应的方法,在Method里面包含一个invoke()方法,该方法的签名如下:

    Object invoke(Object obj,Object... args):该方法中的obj是执行该方法的主调,后面的args是执行该方法时传入该方法的实参。

    下面写一个例子,对象池工厂,简单模拟一下Spring框架的IoC思想。

    obj.txt中:

    a=java.util.Date
    b=javax.swing.JFrame
    b%title=Title

    主代码:

    package demo;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    public class ObjectPoolFactory {
        //定义一个对象池
        private Map<String, Object> objectPool = new HashMap<String, Object>();
        private Properties props = new Properties();
        
        /**
         * 定义一个创建对象的方法
         * @param clazzName
         * @return
         * @throws ClassNotFoundException
         * @throws InstantiationException
         * @throws IllegalAccessException
         */
        private Object createObject(String clazzName) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
            //根据字符串获取对应的class对象
            Class clazz = Class.forName(clazzName);
            //使用clazz对应类的默认构造器创建实例
            return clazz.newInstance();
        }
        
        /**
         * 初始化properties对象
         * @param fileName
         * @throws IOException
         */
        public void init(String fileName) throws IOException{
            FileInputStream fis = new FileInputStream(fileName);
            props.load(fis);
        }
        
        /**
         * 根据指定文件来初始化对象池
         * 它会根据配置文件来创建对象
         * @throws IOException 
         * @throws IllegalAccessException 
         * @throws InstantiationException 
         * @throws ClassNotFoundException 
         */
        public void initPool() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException{
            
            for (String name : props.stringPropertyNames()) {
                //每取出一对key-value对,就根据value创建一个对象
                //调用createObject()创建对象,并将对象添加到对象池中
                System.out.println(name);
                if(!name.contains("%")){
                    objectPool.put(name, createObject(props.getProperty(name)));
                }
            }
        }
        
        /**
         * 该方法根据属性文件来调用指定对象的setter方法
         * @throws SecurityException 
         * @throws NoSuchMethodException 
         * @throws InvocationTargetException 
         * @throws IllegalArgumentException 
         * @throws IllegalAccessException 
         */
        public void initProperty() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
            for (String name : props.stringPropertyNames()) {
                //key用于控制对象的setter方法设置值
                //%前面是对象名字,后面是setter方法名
                if(name.contains("%")){
                    String[] strs = name.split("%");
                    Object target = getObject(strs[0]);
                    String method = "set" + strs[1].substring(0, 1).toUpperCase() +
                            strs[1].substring(1);
                    //获取对象实现类多对应的Class对象
                    Class targetClass = target.getClass();
                    //获取希望调用的setter方法
                    Method mtd = targetClass.getMethod(method, String.class);
                    //通过Method的invoke方法执行setter方法
                    mtd.invoke(target, props.getProperty(name));
                }
            }
        }
        
        /**
         * 获取对象
         */
        public Object getObject(String name){
            //从objectPool中取出指定name对应的对象
            return objectPool.get(name);
        }
        
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
            ObjectPoolFactory pf = new ObjectPoolFactory();
            pf.init("obj.txt");
            pf.initPool();
            pf.initProperty();
            System.out.println(pf.getObject("a"));
            System.out.println(pf.getObject("b"));
        }
        
        
    }

    运行结果:

    b
    a
    b%title
    Wed Apr 27 21:51:20 CST 2016
    javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Title,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]

    窗口的名字也传进来了,说明调用setter方法成功。

  • 相关阅读:
    typeid抛出异常的解释
    [原创]公平数的解法
    [原创]我的北大ACM POJ 1012解答
    [原创]我的PKU ACM POJ1029题解
    asp.net 单用户登录经典解决方案
    [转]SQL事务回滚的问题及其解决的方法
    获取json数据
    js中Date对象的用法
    解决刷新后回到顶部的问题
    C#获取客户端及服务器端主机信息
  • 原文地址:https://www.cnblogs.com/DarrenChan/p/5440549.html
Copyright © 2020-2023  润新知