Java中类加载机制和反射技术

来源:互联网 发布:上升三法选股公式源码 编辑:程序博客网 时间:2024/05/22 06:05

 我们知道一个对象在运行时有两种类型,一个是编译类型,一个是运行时类型。在程序运行时,往往是需要发现类和对象的真实的信息的。那么如何获的这种信息呢?

其一,如果我们在编译和运行时都知道类型的具体信息,这时是可以手动将一个对象转换为运行时的类型。

其二,如果我们在编译时无法预知对象和类到底是属于哪些类,那么程序只有依靠运行时的信息来发现对象和类的真实的信息了,这时就必须要用到反射技术。

在谈具体的发射技术之前,我想先回顾下,有关类的加载的一些基本的性质和原理,以方便我们更好地理解,反射的作用和特点。而实际上,一个类如果可以被执行,那么对于JVM来说,它的执行流程为:类的加载、连接、初始化。通过这种方式,才可以获取到一个类的类对象,即java.lang.Class对象,并在此基础上获取到该类的成员变量,方法和构造器等内在的东东。

   那么,什么是类的加载呢?类的加载就是将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序使用任何类时,系统都会为之建立一个java.lang.Class对象。同时,类的加载是由类加载器完成的。

类的连接:连接阶段负责把类的二进制数据合并到JRE中。第一,验证,检验被加载的类是否有正确的内部结构;第二,准备,负责为类的类变量分配内存,并设置默认初始值。第三,解析将类的二进制数据中的符号引用替换成直接引用。类的初始化,主要对类变量进行初始化。

   这样,我们清楚地认识到了一个类的生命周期变化,那么这些也为我们的反射机制带来了铺垫,要获取一个类的class对象,有三重方式:

       (1)使用Class类的forName(String clazzName)静态方法

       (2)调用某个类的class属性获取该类对应的Class对象

       (3)调用某个类的getClass()方法

       通过这三种手段就可以获取到了一个类的Class对象,这样就可以动态获取该对象的实际的信息了。下面通过一个具体的例子说明下,如果通过反射机制,创建一个类的对象,如何通过获取的对象再进一步获取该对象的属性和方法,以及动态为该对象注入新的参数值。

 

复制代码
 1 package ReflectionEntity; 2 import java.util.Date; 3  4 /** 5  * @author XuJiaqing 6  *  7  */ 8 public class Student { 9     //get/set方法10     public String getStudentID() {11         return studentID;12     }13 14     public void setStudentID(String studentID) {15         this.studentID = studentID;16     }17 18     public String getStudentName() {19         return studentName;20     }21 22     public void setStudentName(String studentName) {23         this.studentName = studentName;24     }25 26     public Date getBirthday() {27         return birthday;28     }29 30     public void setBirthday(Date birthday) {31         this.birthday = birthday;32     }33 34     public int getScore() {35         return score;36     }37 38     public void setScore(int score) {39         this.score = score;40     }41 42     private String studentID;//学生id43     public String studentName;//学生姓名44     private Date birthday;//学生生日45     private int score;//学生成绩46     //实现的任务 的方法47     public void achieveTask(String taskName) {48         System.out.println(studentName + "实现了" + taskName + "技术");49     }50 }
复制代码

 

复制代码
package ReflectionTest;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import ReflectionEntity.Student;/** * @author XuJiaqing *  */public class test {    public static void main(String[] args) {        // TODO Auto-generated method stub        try {            // 获取Student的Class对象            Class<?> clazz = Class.forName("ReflectionEntity.Student");            // 获取该类中所有的属性            Field[] fields = clazz.getDeclaredFields();            // 遍历所有的属性            for (Field field : fields) {                // 打印属性信息,包括访问控制修饰符,类型及属性名                System.out.println(field);                System.out.println("修饰符:"                        + Modifier.toString(field.getModifiers()));                System.out.println("类型:" + field.getType());                System.out.println("属性名:" + field.getName());            }            // 获取该类中的所有方法            Method[] methods = clazz.getDeclaredMethods();            for (Method method : methods) {                // 打印方法签名                System.out.println(method);                System.out.println("修饰符:"                        + Modifier.toString(method.getModifiers()));                System.out.println("方法名:" + method.getName());                System.out.println("返回类型:" + method.getReturnType());                // 获取方法的参数对象                Class<?>[] clazzes = method.getParameterTypes();                for (Class<?> class1 : clazzes) {                    System.out.println("参数类型:" + class1);                }            }            // 通过Class对象创建实例            Student student = (Student) clazz.newInstance();            // 获取属性名为studentName的字段(Field)对象,以便下边重新设置它的值            Field studentName = clazz.getField("studentName");            // 设置studentName的值为”XuJiaqing“            studentName.set(student, "XuJiaqing");            // 通过Class对象获取名为”finishTask“,参数类型为String的方法(Method)对象            Method finishTask = clazz.getMethod("achieveTask", String.class);            // 调用achieveTask方法            finishTask.invoke(student, "反射");        } catch (Exception e) {            e.printStackTrace();        }    }}
复制代码

包的目录结构和运行结果为:

原创粉丝点击