关于利用java反射实现简单的动态java调用

从上周开始,就一直在捣鼓java反射。自己在试着封装一些动态调用java方法的构件。但是总是不是那么如意。一方面,对java反射机制不是那么理解。另一方面,只是为了得到一个公共的java反射方法,然后各种网上找资料。这里,感谢各位网友提供的关于java反射的说明以及代码。这里,要感谢博客园的这篇文章,让我解决了数组反射的问题:Java 反射 Array动态创建数组
下面,先贴一段之前的反射方法:

  protected static HashMap DynamicInvokedSimple(
        HashMap<String, Object> datas, HashMap<String, Object> dynamicInvoke)
        throws Exception {
    HashMap ret = new HashMap();

    if (dynamicInvoke != null && dynamicInvoke.size() > 0) {
        String logicPath = (String) dynamicInvoke
                .get(CommonUtils.DYNAMIC_LOGICPATH);
        String logicType = (String) dynamicInvoke
                .get(CommonUtils.DYNAMIC_LOGICTYPE);
        HashMap paramsMap = (HashMap) dynamicInvoke
                .get(CommonUtils.DYNAMIC_PARAMJSON);

        if (logicPath == null || "".equals(logicPath)) {
            throw new Exception("logicPath不能为空!");
        }

        if (logicType == null || "".equals(logicType)) {
            throw new Exception("logicType不能为空!");
        }

        String classPath = logicPath.substring(0,
                logicPath.lastIndexOf("."));
        String methodName = logicPath
                .substring(logicPath.lastIndexOf(".") + 1);
        Object c;
        try {
            c = Class.forName(classPath).newInstance();
        } catch (Exception e) {
            throw new Exception("创建" + classPath + "实例失败!");
        }

        Object[] paramObjs = new Object[2];
        paramObjs[0] = datas;
        paramObjs[1] = paramsMap;

        try {
            ret = (HashMap) (c.getClass().getMethod(methodName,
                    new Class[] { HashMap.class, HashMap.class }).invoke(c,
                    paramObjs));
            return ret;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("执行" + methodName + "失败!");
        }
    }
    ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
    return ret;
}

先说说这个方法,这个方法第一个参数表示的是传入的参数信息,第二个参数里包含的是反射的java信息,包括java的方法路径,java方法中部分参数信息。

但是这个方法有点局限性。

  1. 需要反射调用的方法必须带有两个Map参数;
  2. 需要反射调用的方法必须返回Map。

在这样的基础上,我决定重新完善下,希望能够得到一个可以定义任意个数参数,任意类型参数,任意返回值类型的方法,并通过java反射机制调用。于是,重新整理下,代码如下:

    protected Map<String, Object> DynamicInvokedSimple(
        List<Object> datas, HashMap<String, Object> dynamicInvoke)
        throws Exception {
    Map ret = new HashMap();

    if (dynamicInvoke != null && dynamicInvoke.size() > 0) {
        String logicPath = (String) dynamicInvoke
                .get(CommonUtils.DYNAMIC_LOGICPATH);
        String logicType = (String) dynamicInvoke
                .get(CommonUtils.DYNAMIC_LOGICTYPE);
        HashMap paramsMap = (HashMap) dynamicInvoke
                .get(CommonUtils.DYNAMIC_PARAMJSON);

        if (logicPath == null || "".equals(logicPath)) {
            throw new Exception("logicPath不能为空!");
        }

        if (logicType == null || "".equals(logicType)) {
            throw new Exception("logicType不能为空!");
        }

        String classPath = logicPath.substring(0,
                logicPath.lastIndexOf("."));
        String methodName = logicPath
                .substring(logicPath.lastIndexOf(".") + 1);
        Object c;
        try {
            c = Class.forName(classPath).newInstance();
        } catch (Exception e) {
            throw new Exception("创建" + classPath + "实例失败!");
        }
        try {
            
            Method[] methods = c.getClass().getDeclaredMethods();  // 获取方法名
            Method methodInfo = null;                              // 定义方法
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                
                /**
                 * 表示一定是有重载方法,那么不仅需要名字匹配,还需要参数个数匹配
                 */
                if (null != dynamicInvoke.get(paramsCountName)) {
                    int methodCount = method.getParameterCount();
                    int paramCount = Integer.parseInt(dynamicInvoke.get(paramsCountName).toString().substring(0,dynamicInvoke.get(paramsCountName).toString().contains(".")?
                            dynamicInvoke.get(paramsCountName).toString().indexOf("."):dynamicInvoke.get(paramsCountName).toString().length()));
                    if (paramCount==methodCount && methodName.equals(method.getName())) {
                        methodInfo = method;
                        break;
                    }
                }else{
                
                    /**
                     * 表示一般的方法
                     */
                    if(methodName.equals(method.getName())){
                        methodInfo = method;
                        break;
                    }
                }
            }
            
            if (null == methodInfo) {
                ret.put(CommonUtils.RETCODE, CommonUtils.FAILURE);
                ret.put(CommonUtils.RETMSG, PARAMSFAILURE+"或"+METHODFAILURE);
                return ret;
            }
            
            /**
             * 获取参数类型
             */
            Class[] types = methodInfo.getParameterTypes();
            Class[] args = new Class[methodInfo.getParameterCount()];
            Object[] paramObjs = new Object[methodInfo.getParameterCount()];
            
            if(null != paramsMap){
                paramObjs[paramObjs.length-1] = paramsMap;
            }
            
            
            if(datas.size() > 0){
                for (int i = 0; i < datas.size(); i++) {
                    paramObjs[i] = datas.get(i);
                }
            }
            
            for (int i = 0; i < paramObjs.length; i++) {
                if (null == paramObjs[i]) {
                    System.out.println(types[i].getName());
                    System.out.println(types[i].getSimpleName());
                    if ("Map".equals(types[i].getSimpleName())) {
                        paramObjs[i] = new HashMap<>();
                    }else if ("List".equals(types[i].getSimpleName())) {
                        paramObjs[i] = new ArrayList<>();
                    }else if ("Set".equals(types[i].getSimpleName())) {
                        paramObjs[i] = new HashSet<>();
                    }else{
                        try {
                            /**
                             * 判断是不是数组
                             */
                            if (Class.forName(types[i].getName()).isArray()) {
                                /**
                                 * 是数组的处理方法
                                 */
                                Class theClass = getClass(types[i].getName());
                                paramObjs[i] = Array.newInstance(theClass, 0);
                            }else{
                                /**
                                 * 如果不是数组的处理方法
                                 */
                                boolean bool = true;
                                for (int j = 0; j < getBasicType().size(); j++) {
                                    String key = getBasicType().get(j);
                                    if (types[i].getName().equals(key)) {
                                        bool = false;
                                        break;
                                    }
                                    
                                }
                                if (bool) {
                                    paramObjs[i] = Class.forName(types[i].getName()).newInstance();
                                }else{
                                    paramObjs[i] = getBasicType(types[i].getName());
                                }
                            }
                            
                        } catch (InstantiationException e) {
                            paramObjs[i] = Class.forName(types[i].getName());
                        } catch (ClassNotFoundException e) {
                            paramObjs[i] = getBasicType(types[i].getName());
                        }
                    }
                }
                
            }
            
            for (int i = 0; i < args.length; i++) {
                args[i] = types[i];
            }
            
            /**
             * 判断方法是否有返回值
             */
            if ("void".equals(methodInfo.getReturnType().getName())) {
                c.getClass().getMethod(methodName,args
                        ).invoke(c,
                        paramObjs);
                ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
                ret.put(CommonUtils.RETMSG, SUCCESS);
                return ret;
            }
            ret.put("data",(c.getClass().getMethod(methodName,args
                    ).invoke(c,
                    paramObjs)));
            ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
            ret.put(CommonUtils.RETMSG, SUCCESS);
            return ret;
        } catch (Exception e) {
            ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
            ret.put(CommonUtils.RETMSG, SUCCESS);
            e.printStackTrace();
            throw new Exception("执行" + methodName + "失败!");
        }
    }
    //ret.put(CommonUtils.RETCODE, CommonUtils.SUCCESS);
    return ret;
}

/**
 * 字节型(byte),短整型(short),整型(int),长整型(long),字符型(char),浮点型(float),双精度型(double),布尔型(boolean)
 * @return
 */
private List<String> getBasicType(){
    List<String> list = new ArrayList<String>();
    list.add("int");
    list.add("byte");
    list.add("short");
    list.add("long");
    list.add("char");
    list.add("float");
    list.add("double");
    list.add("boolean");
    list.add("java.lang.Integer");
    list.add("java.lang.Byte");
    list.add("java.lang.Short");
    list.add("java.lang.Long");
    list.add("java.lang.Character");
    list.add("java.lang.Float");
    list.add("java.lang.Double");
    list.add("java.lang.Boolean");
    return list; 
}

private Object getBasicType(String key){
    if ("int".equals(key)) {
        return 0;
    }else if ("boolean".equals(key)) {
        return false;
    }else if ("byte".equals(key)) {
        return (byte)0;
    }else if ("short".equals(key)) {
        return (short)0;
    }else if ("long".equals(key)) {
        return 0;
    }else if ("char".equals(key)) {
        return (char)0;
    }else if ("float".equals(key)) {
        return 0;
    }else if ("double".equals(key)) {
        return 0;
    }else if ("java.lang.Integer".equals(key)) {
        return new Integer(0);
    }else if ("java.lang.Byte".equals(key)) {
        return new Byte("0");
    }else if ("java.lang.Short".equals(key)) {
        return new Short((short) 0);
    }else if ("java.lang.Long".equals(key)) {
        return new Long(0);
    }else if ("java.lang.Character".equals(key)) {
        return new Character('0');
    }else if ("java.lang.Float".equals(key)) {
        return new Float(0);
    }else if ("java.lang.Double".equals(key)) {
        return new Double(0);
    }else if ("java.lang.Boolean".equals(key)) {
        return new Boolean(false);
    }
    return null;
}


private Class getClass(String className) throws ClassNotFoundException{
      if(className.contains("int")) return int.class;
      if(className.contains("long")) return long.class;
      if(className.contains("boolean")) return boolean.class;
      if(className.contains("byte")) return byte.class;
      if(className.contains("short")) return short.class;
      if(className.contains("char")) return char.class;
      if(className.contains("float")) return float.class;
      if(className.contains("double")) return double.class;
      if(className.contains("String")) return String.class;
      return Class.forName(className);
}

我把第一个参数变成一个list了。也就是,无论多少个参数的方法,都可以通过这个方法的反射去实现。如果本来有5个参数,但是用户只传了3个参数,其他剩余的参数,我将直接赋为初始值。在自己处理的过程中,比较麻烦的是基础数据类型和接口。比如,Map的接口有很多,如何根据传入的参数是Map类型,我要怎么去找到他的实现类来初始化值呢。一般需要初始化值的,是因为用户在传入参数的过程中,没有传入。
我在处理Map这样的jdk中自带的集合的时候,我这里也是直接就根据接口创建为它的实现类hashMap了 。还有基本数据类型,我以为可以通过反射里的某个方法,来初始化,最后,我还是创建了一个集合来存放这些基础信息,再通过传入的数据类型进行匹配。
另一个比较麻烦的就是数组,在反射中,数组的创建和对象实例化还有些不同。还好,最终通过网上提供的资料,终于搞定了这个问题。
一个类里可能出现方法的重载,这个时候通过方法反射的时候,就不知道具体该调用哪个方法了。所以,我在传参的过程中,多加了一个控制参数个数的方法,因为重载的方法,参数个数是不同的,但方法名是相同的。最后这个问题算是解决了。
当然,写这个方法的过程中,还有很多数据类型没有考虑到,比如枚举,注解什么的。要彻底理解反射的原理,可能还需要一段时间。总之,这个方法,现在一般的java方法可以通过反射机制动态调用了。
如果有写的不对的地方,希望大家帮我纠正一下。感激不尽。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 下午四点四十分,苏晓曼和往常一样锁上大门。虽然已经到了秋天,但外面天气还是特别热,她停顿了一下,把衬衣最上面的一颗...
    沈三山阅读 297评论 2 6
  • 对于街乞者,或慈悲,或铁石心肠,每个人的心里都有杆称,我也是持保守态度。以下是一个初出茅庐的实习生于2016年4月...
    竹心竹阅读 236评论 2 0
  • 认识mysql数据库 原地址: http://www.1314sl.com 原地址: http://www.131...
    chcvn阅读 350评论 0 0