zoukankan      html  css  js  c++  java
  • java 强大的反射机制

    这段时间,在对接一个开源的版本时,发现由于依赖的开源版本api老是随着版本的变化而变化,导致代码经常需要修改,异常痛苦。

    终于,在一个风和日丽的下午(五月末的广州异常暴晒),楼主下定决心要修掉这个大篓子。

    在Internet寻找了很久,终于找到了解决方法,参考的文章在本文最后,感谢文章的作者。

    使用java的反射机制,在代码里判断当前运行的是什么版本,然后调用相应的方法。

    这样,代码就做到了自适应。

    假设:

    在自己的代码中,有这么一个工程。

    Function.java

    package chen.test.function;
    
    public class Function{public static void test(String name ){
            System.out.println(name);
            System.out.println("test function have one input");
        }
        public static void test(String name , int id){
            System.out.println(name);
            System.out.println(id);
            System.out.println("test function have two input");
        }
    }

    对上面的Function.java程序编译出一个jar包,名为function.jar

    这个Function类是我自己构造的,为了将Main.java程序编译通过,自己伪造一个方法即可。它有两个test方法,通过参数个数进行重载,但是实际的运行环境里,依赖的jar包中只有一个test方法,可能是两个输入参数的,也有可能是一个输入参数的。

    请看Main.java程序怎么动态识别。

    开发的程序中,依赖function.jar

    Main.java

    package chen.test.client;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    import chen.test.function.Function;
    
    public class Main {
        public static void main(String[] args){
    
            Function aa = new  Function();
            
            tCl( aa );
        }
        /*
        * 本程序是基于JDK1.7 编写,如果使用JDK1.6,那么下面有一些Exception JDK1.6 是不支持的     
        * 不支持的Exception 去除即可     
        */    
        private static void tCl( Object obj ){
            Class<?> classExec = obj.getClass();
            Method exec = null;
            try {            
            //如果运行的jar包支持两个参数的,就运行这个方法            
            //如果运行的jar包不支持两个参数,就进入catch 段,执行输入一个参数的方法
                exec = classExec.getMethod("test", String.class, Integer.class);
                try {
                   String re = (String) exec.invoke( classExec.newInstance(), "chenfool good", 123);
                } catch (IllegalAccessException | IllegalArgumentException
                          | InvocationTargetException | InstantiationException e1) {
                   e1.printStackTrace();
                }
    
            } catch (NoSuchMethodException | SecurityException e) {
                try {                
                   //运行中,依赖的jar包,不支持两个参数,导致进入此段代码                
                   //运行只有一个输入参数的函数
                   exec = classExec.getMethod("test", String.class);                                   
                   try {
                      String re = (String) exec.invoke( classExec.newInstance(), "chenfool good");
                   } catch (IllegalAccessException | IllegalArgumentException
                              | InvocationTargetException | InstantiationException e1) {
                      e1.printStackTrace();
                   }
       
                } catch (NoSuchMethodException | SecurityException e1) {
                   e1.printStackTrace();
                }
            }
        }
    }

    上面的Main.java程序虽然可以通过,但是方法中有一个缺陷,当Function类是不可构建的时,方法就不能通过了,它会报Function.class.getInterfaces()出错。

    拥有私有构建函数的Function.java

    package chen.test.function;
    
    public class Function{
        private Function(){
    
        }
        public static void test(String name ){
            System.out.println(name);
            System.out.println("test function have one input");
        }
        public static void test(String name , int id){
            System.out.println(name);
            System.out.println(id);
            System.out.println("test function have two input");
        }
    }

    这时,我们就要用别的方法来解决这个问题。

    考虑,我们的目的就是判断当前运行的环境中,Function.test方法的输入参数是一个还是两个,所以我们使用getDeclaredMethod()方法,通过是否抛出异常来区分究竟是调用哪个test方法。

    改进版本的Main.java程序

    package chen.test.client;
    
    import java.lang.reflect.Method;
    
    import chen.test.function.Function;
    
    public class Main {
      public static void main(String[] args){
    
        Class[] parameterTypes = new Class[2];
        parameterTypes[0] = String.class;
        parameterTypes[1] = int.class;
        try {
          //如果没有抛出异常,则证明此环境的Function类是调用两个参数的方法
          //如果抛出异常,则调用一个输入参数的test方法
          Method method = Function.class.getDeclaredMethod("test", parameterTypes);
          Function.test("chenfool is great", 123);
        } catch (SecurityException e) {
          e.printStackTrace();
        } catch (NoSuchMethodException e) {
          parameterTypes = new Class[1];
          parameterTypes[0] = String.class;
          Method method = null;
          try {
            //系统捕获异常,证明此运行环境调用的是一个输入参数的test方法
            method = Function.class.getDeclaredMethod("test", parameterTypes);
            Function.test("chenfool is good");
          } catch (SecurityException e1) {
            e1.printStackTrace();
          } catch (NoSuchMethodException e1) {
            e1.printStackTrace();
          }
    
        }
    
      }
    
    }

    通过java的反射机制,我们就能动态的调用相应的方法,而无需因为依赖jar包的Api不兼容,导致开发多个程序来适配对应不同版本的Api,这样项目工程一旦变大,或者时间拉长,程序的维护成本会越来越高。

    参考文章:

    http://hi.baidu.com/vcxsloxuvibilyd/item/57b4da6bdcdc46106995e605

  • 相关阅读:
    oraclesqlloader
    Dosinternal command and external command
    unixexpr
    Powerbuilder 6.5完全图解教程
    character set
    pbdatawindow function
    java decompile tool(recommended)
    php验证码背景色设置无效
    使用jquery validation engine判断为空的时候要根据input的type
    有些站点不能被iframe
  • 原文地址:https://www.cnblogs.com/chenfool/p/3755652.html
Copyright © 2011-2022 走看看