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

  • 相关阅读:
    真正的e时代
    在线手册
    UVA 10616 Divisible Group Sums
    UVA 10721 Bar Codes
    UVA 10205 Stack 'em Up
    UVA 10247 Complete Tree Labeling
    UVA 10081 Tight Words
    UVA 11125 Arrange Some Marbles
    UVA 10128 Queue
    UVA 10912 Simple Minded Hashing
  • 原文地址:https://www.cnblogs.com/chenfool/p/3755652.html
Copyright © 2011-2022 走看看