Java技术——Java反射机制分析

1. Java的反射机制

动态语言是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言。但Java它却有着一个非常突出的动态相关机制:反射

 

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

 

Java反射机制主要提供了以下功能

(1)在运行时判断任意一个对象所属的类

(2)在运行时构造任意一个类的对象

(这一条在下面没有展示实例,但在之前写过的一篇Java中创建对象的5种方式中有所介绍,有兴趣的可以参考查看。)

(3)在运行时判断任意一个类所具有的成员变量和方法

(4)在运行时调用任意一个对象的方法

(5)生成动态代理

 

2. Java反射API

反射API用来生成在当前Java虚拟机中的类、接口或者对象的信息。

Class类:反射的核心类,可以获取类的属性,方法等内容信息。

Field类:Java.lang.reflect.表示类的属性,可以获取和设置类的中属性值

Method类:Java.lang.reflect。表示类的方法,它可以用来获取类中方法的信息或者执行方法

Construcor类:Java.lang.reflect。表示类的构造方法

 

3.反射常见用法

3.1 判断对象是否属于反射得到的类(isInstance

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. class S {     
  2. }      
  3. public class IsInstance {     
  4.    public static void main(String args[]) {     
  5.       try {     
  6.            Class cls = Class.forName("S");  //创建了一个S类的Class对象  
  7.            boolean b1 = cls.isInstance(new Integer(37));     
  8.            System.out.println(b1);   //fasle  
  9.            boolean b2 = cls.isInstance(new S());     
  10.            System.out.println(b2);   //true  
  11.       }     
  12.       catch (Throwable e) {     
  13.            System.err.println(e);     
  14.       }     
  15.    }     
  16. }   


3.2 获取某个反射类的所有属性字段

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  * 获取反射类的所有属性字段  
  3.  *   
  4.  * @param ownerClass 反射的类  
  5.  * @return  
  6.  * @throws Exception  
  7.  */    
  8. public Field[] getProperty(Class ownerClass) throws Exception {    
  9.     
  10.     //获取该类所有属性字段    
  11.     //Field[] fields = ownerClass.getFields();//只获取public访问权限的属性字段(包括父类的)    
  12.     Field[] fields = ownerClass.getDeclaredFields();//只获取该类的所有访问权限的属性(不含父类)    
  13.         
  14.     //输出所有属性字段    
  15.     for(int i=0;i<fields.length;i++){    
  16.         System.out.println("属性:"+fields[i]);    
  17.     }    
  18.     
  19.     return fields;    
  20. }    

3.3 获取反射类的某个public属性值

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  * 获取反射类的某个public属性值  
  3.  *   
  4.  * @param ownerClass 反射的类  
  5.  * @param fieldName 属性名  
  6.  * @return  
  7.  * @throws Exception  
  8.  */    
  9. public Object getProperty(Object owner,String fieldName) throws Exception {    
  10.         
  11.     //得到对象所属类    
  12.     Class ownerClass = owner.getClass();    
  13.     
  14.     //获取该类的某个属性    
  15.     Field field = ownerClass.getField(fieldName);    
  16.         
  17.     //获取某个对象的特定属性    
  18.     Object property = field.get(owner);    
  19.         
  20.     //输出该属性信息    
  21.     System.out.println(fieldName+"的属性值:"+property.toString());    
  22.     
  23.     return property;    
  24.     
  25. }    


3.4 获取反射类的该中的所有方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  * 获取反射类的该中的所有方法  
  3.  * @param ownerClass 反射的类  
  4.  * @return  
  5.  * @throws Exception  
  6.  */    
  7. public Method[] getMethods(Class ownerClass) throws Exception {    
  8.     
  9.     //获取该类所有方法    
  10.     //Field[] fields = ownerClass.getMethods();//只获取public访问权限的方法(包括父类的)    
  11.     Method[] methods = ownerClass.getDeclaredMethods();//只获取该类的所有访问权限的方法(不含父类)    
  12.     
  13.     //输出所有方法    
  14.     for(int i=0;i<methods.length;i++){    
  15.         System.out.println("方法:" +methods[i]);    
  16.     }    
  17.     
  18.     return methods;    
  19. }    


3.5 执行反射类的该中的某个方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  * 执行反射类的该中的某个方法  
  3.  * @param ownerClass 反射的类  
  4.  * @param methodName 方法名  
  5.  * @return  
  6.  * @throws Exception  
  7.  */    
  8. public Object invokeMethod(Object owner,String methodName,Object[] args) throws Exception {    
  9.     
  10.     //得到对象所属类    
  11.     Class ownerClass = owner.getClass();    
  12.     
  13.     //获取该类的某个方法    
  14.     Method method = ownerClass.getMethod(methodName, null);    
  15.         
  16.     //执行某个对象的方法    
  17.     Object result = method.invoke(owner, args);    
  18.         
  19.     //输出结果信息    
  20.     System.out.println("结果返回值:"+ result);    
  21.     
  22.     return result;    
  23. }    


实例演示方法:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  * 测试反射常用方法  
  3.  */    
  4. public void refTest(){    
  5.     String className = "com.java.reflecttest.Student";    
  6.     
  7.     try {    
  8.             
  9.         //通过反射机制,使用类装载器,装载该类    
  10.         Class<?> stu = Class.forName(className);    
  11.         Object objStu = stu.newInstance();    
  12.                     
  13.             
  14.         //获取反射类的所有属性    
  15.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  16.         System.out.println("调用 getProperty 方法,获取Student类的所有属性");    
  17.         getProperty(stu);    
  18.             
  19.             
  20.         //获取反射类的某个属性值    
  21.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  22.         System.out.println("调用 getProperty 方法,获取Student类的NAME属性值");    
  23.         getProperty(objStu,"NAME");    
  24.             
  25.             
  26.         //获取反射类的所有方法    
  27.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  28.         System.out.println("调用 getMethods 方法,获取Student类的所有方法");    
  29.         getMethods(stu);    
  30.             
  31.         //执行反射类的getInfo方法    
  32.         System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");    
  33.         System.out.println("调用 invokeMethod 方法,执行Student类的getInfo方法");    
  34.         invokeMethod(objStu, "getInfo"null);    
  35.             
  36.             
  37.     } catch (Exception e) {    
  38.         e.printStackTrace();    
  39.     }    
  40. }    

演示所用的Student类:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.java.reflecttest;    
  2.     
  3. /**  
  4.  * 学生信息类  
  5.  *   
  6.  * @author Longxuan  
  7.  *  
  8.  */    
  9. public class Student {    
  10.     
  11.     /**  
  12.      * 学号  
  13.      */    
  14.     private String stuId ;    
  15.         
  16.     /**  
  17.      * 学号  
  18.      */    
  19.     public String STUID;    
  20.         
  21.     /**  
  22.      * 姓名  
  23.      */    
  24.     private String name ;    
  25.         
  26.     /**  
  27.      * 姓名  
  28.      */    
  29.     public String NAME;    
  30.     
  31.     /**  
  32.      * 年龄  
  33.      */    
  34.     private int age;    
  35.         
  36.     /**  
  37.      * 年龄  
  38.      */    
  39.     public int AGE;    
  40.         
  41.     /**  
  42.      * 班级  
  43.      */    
  44.     private String classid;    
  45.         
  46.     
  47.     
  48.         
  49.     public String getStuId() {    
  50.         return stuId;    
  51.     }    
  52.     
  53.     public void setStuId(String stuId) {    
  54.         this.stuId = stuId;    
  55.     }    
  56.     
  57.     public String getName() {    
  58.         return name;    
  59.     }    
  60.     
  61.     public void setName(String name) {    
  62.         this.name = name;    
  63.     }    
  64.     
  65.     public int getAge() {    
  66.         return age;    
  67.     }    
  68.     
  69.     public void setAge(int age) {    
  70.         this.age = age;    
  71.     }    
  72.     
  73.     public String getClassid() {    
  74.         return classid;    
  75.     }    
  76.     
  77.     public void setClassid(String classid) {    
  78.         this.classid = classid;    
  79.     }    
  80.         
  81.         
  82.     /**  
  83.      * 输出学生信息  
  84.      */    
  85.     public void getInfo(){    
  86.         System.out.println("学生信息:\n学号:"+stuId+"\t姓名:"+name+"\t年龄:"+age+"\t班级:"+classid);    
  87.     }    
  88.         
  89.     /**  
  90.      * 构造函数  
  91.      */    
  92.     public Student(){    
  93.         init();    
  94.     }    
  95.         
  96.         
  97.     /**  
  98.      * 私有初始化方法  
  99.      */    
  100.     private void init(){    
  101.         this.name = "张三";    
  102.         this.stuId ="1001";    
  103.         this.age = 14;    
  104.         this.classid = "A001";    
  105.         this.NAME = name;    
  106.         this.AGE = age;    
  107.         this.STUID = stuId;    
  108.     }    
  109.         
  110. }    


运行结果:


4. 反射的效率

在Stackoverflow上认为反射比较慢的程序员主要有如下看法,如果你面试遇到了,可以这样回答:

(1)验证等防御代码过于繁琐,这一步本来在link阶段,现在却在计算时进行验证。

(2)产生很多临时对象,造成GC与计算时间消耗。

(3)由于缺少上下文,丢失了很多运行时的优化,比如JIT(它可以看作JVM的重要评测标准之一)

 

当然,我个人的看法是,现代JVM也不是非常慢了,它能够对反射代码进行缓存以及通过方法计数器同样实现JIT优化,所以反射不一定慢。更重要的是,很多情况下,你自己的代码才是限制程序的瓶颈。因此,在开发效率远大于运行效率的的基础上,大胆使用反射,放心开发吧。


文章转自:http://blog.csdn.NET/xiaoxian8023/article/details/9206055

http://www.jianshu.com/p/f83556bcae59

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章