`
wanglihu
  • 浏览: 908862 次
  • 性别: Icon_minigender_1
  • 来自: 黑龙江
社区版块
存档分类

java反射机制

    博客分类:
  • java
阅读更多

    Java提供的反射机制允许你在运行时动态加载类、查看类信息、生成对象或操作生成的对象。在整合式开发环境中所提供的方法提示或是泪查看工具,还有象JSP中的JavaBean自动收集请求信息也使用到反射,而一些软件开发框架(Framework)也常见到反射机制的使用,以达到动态加载使用者自定义类的目的。反射其实就是程序能够自检查自身信息。就像程序会照镜子反光看自己。
在程序中可以检查某个类中的方法属性等信息,并且能够动态调用。 这样可以写出很灵活的程序。 比如要把一个对象中的数据copy到另外一个对象中,规则是属性名相同就copy, 就可以用反射来做,不需要指定每个属性的名字,只要动态从类中取得信息,
再判断属性名是否相同即可。当然应用还有很多。 反射可以结合Java的字节码,使用ASM和cglib等库,还能动态生成类。
hibernate的延迟载入,spring的AOP都是这么实现的 。反射给Java带来了一些动态性。不过虽然很好,但毕竟还是有一定局限性的。另外ASM,cglib使用还是不放便。因此一些纯动态语言现在是一个重要发展趋势,比如ruby,python等,程序很容易动态生成。

    那到底什么叫反射机制呢?

   1. java程序在运行时可以获得任何一个类的字节码信息,包括类的修饰符(public,static等),基类(超类,父类),实现的接口,字段和方法等信息。
   2. java程序在运行时可以根据字节码信息来创建该类的实例对象,改变对象的字段内容和调用对象方法.
我们把上面这种机制就叫反射技术。因为Java在真正需要使用一个类的时候才会加以加载,而不是在程序启动时就加载所有的类。大多数使用者都只使用到应用程序的部分资源,在需要某些功能时才加载某些资源,可以让系统的资源运用更有效率(Java本身就是为了资源有限的小型设备而设计的,这样的考虑是必然的)。
   
Java的反射机制是通过反射API来实现的,它允许程序在运行过程中取得任何一个已知名称的类的内部信息.反射API位于java.lang.reflect包中.主要包括以下几类:
         1).Constructor类:用来描述一个类的构造方法
        2).Field类:用来描述一个类的成员变量
        3).Method类:用来描述一个类的方法.
        4).Modifer类:用来描述类内各元素的修饰符
        5).Array:用来对数组进行操作.
获取类的构造方法的Constructor对象(数组)
    Constructor[] getDeclaredConstructors();返回已加载类声明的所有的构造方法的Constructor对象数组.
   Constructor getDeclaredConstructor(Class[] paramTypes);返回已加载类声明的指定构造方法的Constructor对象,paramTypes指定了参数类型.
   Constructor[] getConstructors();返回已加载类声明的所有的public类型的构造方法的Constructor对象数组.
    Constructor getConstructor(Class[] paramTypes);返回已加载类声明的指定的public类型的构造方法的Constructor对象,paramTypes指定了参数类型.
如果某个类中没有定义构造方法,第一个和第三个方法返回的数组中只有一个元素,就是缺省的构造方法;如果某个类中只定义了有参数的构造函数,而没有定义缺省构造函数,第一个和第三个方法返回的数组中不包含缺省的构造方法.
例子:
package com.vincent.test;
import java.lang.reflect.*;
public class DumpMethods {
    
public static void main(String[] args) {
        
try {
            
if (args.length < 1) {
                 System.out.println(
"请输入完整的类名:");
                
return;
             }
             Class strClass
= Class.forName(args[0]);
            
//检索带有指定参数的构造方法
             Class[] strArgsClass = new Class[]{byte[].class, String.class};
             Constructor constructor
= strClass.getConstructor(strArgsClass);
             System.out.println(
"Constructor:" + constructor.toString());
            
//调用带有参数的构造方法创建实例对象object
            byte[] bytes = "IT年薪".getBytes();
             Object[] strArgs
= new Object[]{bytes, "GBK"};
             Object object
= constructor.newInstance(strArgs);
             System.out.println(
"Object" + object.toString());
         }
catch (Exception e) {
             e.printStackTrace();
         }
     }
}

 

Field[] getDeclaredFields():返回已加载类声明的所有成员变量的Field对象数组,不包括从父类继承的成员变量.

Field getDeclaredField(String name):返回已加载类声明的所有成员变量的Field对象,不包括从父类继承的成员变量,参数name指定成员变量的名称.

   Field[] getFields():返回已加载类声明的所有public型的成员变量的Field对象数组,包括从父类继承的成员变量
   Field getField(String name):返回已加载类声明的所有成员变量的Field对象,包括从父类继承的成员变量,参数name指定成员变量的名称.
例子:
package com.vincent.test
import java.lang.reflect.*;
public class ReflectTest {
        
private String name;
        
private String passwd;
        
public ReflectTest(String name,String passwd){
               
this.name=name;
               
this.passwd=passwd;
         }

        
public static void main(String[] args) {
             
try{
                   ReflectTest rt
=new ReflectTest("Vincent","spring");
                   fun(rt);
              }
catch(Exception e){
                      e.printStackTrace();
              }
        }
        
public static void fun(Object obj) throws Exception{
                Field[] fields
=obj.getClass().getDeclaredFields();
                System.out.println(
"修改之前的值:");
               
for(Field field:fields){
                     System.out.println(field.getName()
+"="+field.get(obj));
                   
if(field.getType().equals(java.lang.String.class)){
                         
//必须设置为true才可以修改成员变量
                          field.setAccessible(true);                              String org=(String)field.get(obj);
                          field.set(obj,org.replaceAll(
"g","a"));
                    }
          }
          System.out.println(
"修改之后的值:");
         
for(Field field:fields){
                 System.out.println(field.getName()
+"="+field.get(obj));
          }
       }
}

 

获取类的方法的Method对象(数组)
    Method[] getDeclaredMethods():返回已加载类声明的所有方法的Method对象数组,不包括从父类继承的方法.
    Method getDeclaredMethod(String name,Class[] paramTypes):返回已加载类声明的所有方法的Method对象,不包括从父类继承的方法,参数name指定方法的名称,参数paramTypes指定方法的参数类型.
   Method[] getMethods():返回已加载类声明的所有方法的Method对象数组,包括从父类继承的方法.
   Method getMethod(String name,Class[] paramTypes):返回已加载类声明的所有方法的Method对象,包括从父类继承的方法,参数name指定方法的名称,参数paramTypes指定方法的参数类型.
检索类的其他信息
   int   getModifiers():返回已加载类的修饰符的整形标识值.
   Package getPackage():返回已加载类的包名
   Class   getSuperclass():返回已加载类的父类的Class实例.
   Class []   getInterfaces():返回已加载类实现的接口的Class对象数组.
   boolean isInterface():返回已加载类是否是接口.
有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定(dynamic binding)、动态链接(dynamic linking)、动态加载(dynamic loading)等。然而“动态”一词其实没有绝对而普遍适用的严格定义,有时候甚至像对象导向当初被导入编程领域一样,一人一把号,各吹各的调。
 
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,答应改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
 
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods1。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
 
Java如何能够做出上述的动态特性呢?这是一个深远话题,本文对此只简单介绍一些概念。整个篇幅最主要还是介绍Reflection APIs,也就是让读者知道如何探索class的结构、如何对某个“运行时才获知名称的class”生成一份实体、为其fields设值、调用其methods。本文将谈到java.lang.Class,以及java.lang.reflect中的Method、Field、ConstrUCtor等等classes。
 
“Class”class
众所周知Java有个Object class,是所有Java classes的继续根源,其内声明了数个应该在所有Java class中被改写的methods:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class object。
 
Class class十分非凡。它和一般classes一样继续自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及要害词void。当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object。假如您想借由“修改Java标准库源码”来观察Class object的实际生成时机(例如在Class的constructor内添加一个println()),不能够!因为Class并没有public constructor(见图1)。本文最后我会拨一小块篇幅顺带谈谈Java标准库源码的改动办法。
      Class是Reflection故事起源。针对任何您想探勘的class,唯有先为它产生一个Class object,接下来才能经由后者唤起为数十多个的Reflection APIs。这些APIs将在稍后的探险活动中一一亮相。
 
public final class Class<T> implements java.io.Serializable,java.lang.reflect.GenericDeclaration,java.lang.reflect.Type,java.lang.reflect.AnnotatedElement {
  private Class() {}
  public String toString() {
   return ( isInterface() ? "interface " :
     (isPrimitive() ? "" : "class "))
  + getName();
 }
注重它的private empty ctor,意指不答应任何人经由编程方式产生Class object。是的,其object 只能由JVM 产生。
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics