第一次感受DI(Dependency Injection) & java.lang.reflect.* 学习                           糊涂鬼 2005-05-12   说是说感受一下这个东西DI(也可以说是IoC-(Inversion of Control)吧),其实我对它的认识只有一点点,甚至说我今天写的这个程序有没有用到它我都不敢肯定,只是我感觉我是用到了的。好了,废话我不多说了,先把两个程序贴出来,浏览一下,别细读。 | Program 1(without DI): | Program 2(with DI): |  package cn.liltos.reflect; import java.lang.reflect.*; public class GetClassInfo_1 {     public static void main(String[] args) {         long start = System.currentTimeMillis();         String s = "cn.liltos.reflect.Beans";         getClassName(s);         getFields(s);         getConstructor(s);         getMethods(s);         System.out.println("}");         long end = System.currentTimeMillis();         long cost = end - start;         System.out.println("this program last : " + cost);     }         public static void getConstructor(String s) {         System.out.println("\n    //构造方法");         Class c = getClass(s);         Constructor[] constructor = c.getConstructors();         printObjectArray(constructor);     }     public static void getMethods(String s) {         System.out.println("\n    //成员方法\n");         Class c = getClass(s);         Method[] method = c.getDeclaredMethods();         printObjectArray(method);     }     public static void getFields(String s) {         System.out.println("{\n    //成员变量");         Class c = getClass(s);         Field[] field = c.getFields();         printObjectArray(field);     }     public static void getClassName(String s) {         System.out.print("class ");         String className = getClass(s).getName();         System.out.println(className);     }     public static Class getClass(String s) {         Class c;         try {             c = Class.forName(s);         } catch(ClassNotFoundException ex) {             return null;         }         return c;     }     public static void printObjectArray(Object[] obj) {         for(int i = 0; i < obj.length; ++i) {             System.out.println("    " + obj[i]);         }     } } | package cn.liltos.reflect; import java.lang.reflect.*; public class GetClassInfo_2 {     public static void main(String[] args) {         long start = System.currentTimeMillis();         String s = "cn.liltos.reflect.Beans";         Class c = getClass(s);         getClassName(c);         getFields(c);         getConstructor(c);         getMethods(c);         System.out.println("}");         long end = System.currentTimeMillis();         long cost = end - start;         System.out.println("this program last : " + cost);     }     public static void getMethods(Class c) {         System.out.println("\n    //成员方法");         Method[] method = c.getDeclaredMethods();         printObjectArray(method);     }     public static void getFields(Class c) {         System.out.println("{\n    //成员变量");         Field[] field = c.getFields();         printObjectArray(field);     }         public static void getConstructor(Class c) {         System.out.println("\n    //构造方法");         Constructor[] constructor = c.getConstructors();         printObjectArray(constructor);     }     public static void getClassName(Class c) {         System.out.print("class ");         System.out.println(c.getName());     }     public static Class getClass(String s) {         Class c;         try {             c = Class.forName(s);         } catch(ClassNotFoundException ex) {             return null;         }         return c;     }     public static void printObjectArray(Object[] obj) {         for(int i = 0; i < obj.length; ++i) {             System.out.println("    " + obj[i]);         }     } } |  
   这两个程序我把注释全部删除了,对于一个如此简单的程序,实在没有必要把注释都写出来,我想我的命名应该还是可以的,看方法名就可以知道方法是做什么的吧(:-),有点臭美,容忍一下)。   另外程序还涉及到一个叫‘cn.liltos.reflect.Beans’的类,看名字就知道啦,这个类里面无非也就是一些 field 和一些 method,再没有其它什么值得注意的东东了。   现在说一下这两个程序是用途,运用JAVA的反射机制,读取想查看的类(这里是cn.liltos.reflect.Beans)的一些细节,并将得到的结果打印在屏幕上。为了打印出来的东西具有一定的可读性,我在程序里便有了那些不美观的、一大堆的换行控制。同时,为了检查程序的执行时间,在 main() 的开始和结束都调用了 System.currentTimeMillis() 来确定时间。最后输出程序的执行时间。在程序里运用的反射的几个方法也比较简单。我晕,又说了一堆废话 :-(   两个程序的方法(均为 static),相同的有 void printObjectArray(Object[] obj)、Class getClass(String s)、void main(String[] args)。而其它的方法,只有名字是相同的,参数则不一样。第一个程序里其它的方法的参数都是 String s, 而后者则是以 Class c 为参数,这也是我认为后者采用的是 DI 的原因,方法体都是根据传入的参数所代表的类去寻找类的细节。   看一个JAVA程序的运行效率有多高,一般是看第一次运行的,这个观点不知道是否正确,因为如果JVM一次次地运行同一个程序的话,它会一次次的优化字节码,相信有很多朋友有这样的经验,编译同一个程序,第二次编译的时间会很明显地比第一次编译花的时间少。对于运行,同理可证。呵呵~~~~   那这上面的两个程序的效率到底差了多少呢?在第一次运行的时候,Program 1 花了 7000 多 Milliseconds ,而 Program 2 只花了 170 个单位。这个数字有点吓人会吗?反正我执行完第二个程序后看到的这个数字差时是被吓了一跳。不过在运行了将近十次以后,两个程序的时间差少了非常非常之多,只有 40 个单位的时间了。   40 Milliseconds,这个数字太不大了,呵呵,才40,只要我的机器配置再高一些,这点时间,压根就感觉不到,确实,一点都没错。但是——最讨厌看到一堆美好之词后面加这个词了——但是,这只是一个非常小的程序,非常非常小。如果现在运行的不是一个程序,而是一组、或是几个 package 的程序,那么这个时间就非常之可观了,不是么?   看到这里了,先打住,有一件事情我不敢确定,上面的程序有用到 DI 的思想吗?恳请高手指点一下,我实在是没什么自信。    相信有很多朋友对于那些高手们左口一个 IoC 右口一个 DI 一定感到很羡慕,羡慕人家知道那么多东西。如果到这里我上面的程序确实有用到 DI 的思想的话,那么,请允许我班门弄斧似滴说一下上面在什么地方用到了 DI 吧。
     public static void getMethods(String s) {         System.out.println("\n    //成员方法\n");         Class c = getClass(s);         Method[] method = c.getDeclaredMethods();         printObjectArray(method);     }   这一段程序,为了得到 s 代表的类的自己声明的方法,参数 String s 是类在 classpath 上的位置。进入方法体后,再用 Class c = getClass(s); 得到 Class 类的实例,然后调用 c.getDeclaredMethods() 得到这个实例自己声明的方法。   与之对应的另一个方法如下:     public static void getMethods(Class c) {         System.out.println("\n    //成员方法");         Method[] method = c.getDeclaredMethods();         printObjectArray(method);     }   参数直接变成了 Class c,也就是说,直接把 Class 的实例注入方法,而不是在方法中再去寻找/创建。在这个小程序中,外在的好处只是处理时间减少了一点点,但是,将控制权从方法内部转移到外部,减少方法需要做的工作,便意味着一个提高。有一点是必须注意的尽量简化方法,让一个方法只做好自己本职的那份工作,是面向对象的一个很基本的原则,可以提高代码的复用率。虽然只是一个方法的重用,但养成一个好习惯会比较好一点。  
 
  |