浅析Java中的反射机制原理

来源:互联网 发布:淘宝红号查询 编辑:程序博客网 时间:2024/04/25 16:24

http://blog.csdn.net/xiaoxian8023/article/details/9154227  

反射反射,程序员的快乐!

       Java中反射机制使用的还是比较广泛的,系统的灵活性、可扩展性大都都是通过反射等方式来加载外部插件,使得系统与插件解耦的同时,增加了功能。但是很多人都只是会用,却是不知道它的实现机制,今天就由我来带大家揭开反射机制的神秘面纱。

       Java中是用Class.forName(classname)来反射类。


[java] view plaincopy
  1. package com.java.reflecttest;  
  2.   
  3. import com.java.dbtest.DBTest;  
  4.   
  5.   
  6. /** 
  7.  * Java反射机制测试 
  8.  * @author Longxuan 
  9.  * 
  10.  */  
  11. public class ReflectTest {  
  12.   
  13.     /** 
  14.      * 测试反射类 
  15.      */  
  16.     public static void refTest(){  
  17.         String className = "com.java.dbtest.TestConnection";  
  18.         DBTest dbTest = null;  
  19.         try {  
  20.               
  21.             //通过反射机制,使用类装载器,装载该类  
  22.             Class tc = Class.forName(className);  
  23.               
  24.             //输出反射得到的类  
  25.             System.out.println(tc);  
  26.               
  27.             //创建该类的实例,转化为接口  
  28.             dbTest =(DBTest)tc.newInstance();  
  29.               
  30.             //通过接口,调用该类的方法  
  31.             dbTest.SelectUser();  
  32.               
  33.         } catch (ClassNotFoundException e) {  
  34.             e.printStackTrace();  
  35.         } catch (InstantiationException e) {  
  36.             e.printStackTrace();  
  37.         } catch (IllegalAccessException e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.           
  41.     }  
  42.       
  43.     public static void main(String[] args){  
  44.         refTest();  
  45.     }  
  46. }  


       通过main函数的调试,已经通过,结果如图:

       

       经过调试,查资料,结合自己的推测和理解,似乎是明白了一些。现与大家分享讨论。

       先说执行过程:

       Class.forName(classname)方法,实际上是调用了Class类中的 Class.forName(classname, true, currentLoader)方法。参数:name - 所需类的完全限定名;initialize - 是否必须初始化类;loader - 用于加载类的类加载器。currentLoader则是通过调用ClassLoader.getCallerClassLoader()获取当前类加载器的。类要想使用,必须用类加载器加载,所以需要加载器。反射机制,不是每次都去重新反射,而是提供了cache,每次都会需要类加载器去自己的cache中查找,如果可以查到,则直接返回该类。


       有意思的是java的类加载器也有些门道。它分为BootStrap Class Loader(引导类加载器),Extensions Class Loader (扩展类加载器),App ClassLoader(或System Class Loader),当然少不了Custom ClassLoader(用户自定义类加载器)。其加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。类加载器的详细介绍会在接下来的博文中较深入的分析,欢迎期待。


       forName方法中,调用了ClassLoader.loadClass方法来完成类的反射。根据类加载器的特殊性,结合我的调试过程,画了一个简单的流程图,



       我的这幅图简单的说明了类加载器的类加载过程。先检查自己是否已经加载过该类,如果加载过,则直接返回该类,若没有则调用父类的loadClass方法,如果父类中没有,则执行findClass方法去尝试加载此类,也就是我们通常所理解的片面的"反射"了。这个过程主要通过ClassLoader.defineClass方法来完成。defineClass 方法将一个字节数组转换为 Class 类的实例(任何类的对象都是Class类的对象)。这种新定义的类的实例需要使用 Class.newInstance 来创建,而不能使用new来实例化。

 

      为什么说“任何类的对象都是Class类的对象”呢?在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类(.java文件),编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。


       其实说的简单通俗一点,就是在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。


       以上内容是我经过调试、查java Api和网上资料,结合自己的理解,与大家分享讨论的,如果有错,欢迎大家指正,我们共同进步。

0 0