什么是反射
反射机制指的是程序在运行时能够获取自身的信息即在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。反射是Java的特征之一,是一种间接操作目标对象的机制。
反射的基础之class
Class类是反射实现的基础,要想理解反射,首先要理解Class类。在程序运行期间,虚拟机为所有的对象维护一个被称为运行时的类型标识,这个信息跟踪着每个对象所属的类的完整结构信息,包括包名、类名、实现的接口、拥有的方法和字段等。可以通过特殊的Java类访问这些信息,这个类就是Clas 类。可以把Class类理解为类的类型,一个Class对象,称为类的类型对象,一个Class对象对应一个加载到JVM中的一个.class文件。
publicfinalclassClass<T>implementsjava.io.Serializable,GenericDeclaration,Type,AnnotatedElement{privatestaticfinalintANNOTATION=0x00002000;privatestaticfinalintENUM=0x00004000;privatestaticfinalintSYNTHETIC=0x00001000;privatestaticnativevoidregisterNatives();static{registerNatives();}...}
首先JVM会将代码编译成一个.class字节码文件,然后被类加载器(Class Loader)加载进JVM的内存中,同时会创建一个类的Class对象存到堆中(注意这个不是new出来的对象,而是类的类型对象)。JVM在创建类对象前,会先检查其类是否加载,寻找类对应的Class对象,若加载好,则为其分配内存,然后再进行初始化。
在加载完一个类后,堆内存的方法区就产生了一个Class对象,这个对象就包含了完整的类的结构信息,通过这个Class对象可以看到类的结构,就好比一面镜子。所以称之为:反射。
反射的基本使用
反射机制的常用的类
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
反射常用的API
对象. setAccessible(true);
Class:
获取公开属性:getField("属性名");
获取私有属性:getDeclaredField("属性名");
通过指定方法名称获取公开无参方法对象:getMethod("方法名", null);
获取所有公开方法对象:getMethods();
获取所有方法对象:getDeclaredMethods();
通过指定方法名称获取私有有参方法对象:getDeclaredMethod("方法名", 方法参数的类型......);
调用公开有参构造:getConstructor(构造参数类型);
调用私有有参构造:getDeclaredConstructor(构造参数类型);
判断是否是某个类的实例:isInstance(obj);
Field:
获取属性名:getName();
获取属性的类型:getType();
获取属性的修饰符:getModifiers();
设置属性值 1:类实例化对象 要设置的参数值:set(obj,obj);
Method:
方法对象.invoke(类实例化对象, 方法的参数数组); //执行方法
Constructor:
NewInstance();//通过构造获取到类的实例对象
下面看代码:
publicclassTest(){Aa=newA();Classc1=A.class;//任何一个类都有一个隐含的静态成员变量classClassc2=a.getClass();//在已知类的对象的情况下通过getClass方法获取Classc3=null;try{c3=Class.forName("com.xxxx.A");//类的全称}catch(ClassNotFoundExceptione){e.printStackTrace();}}classA{}
方法的反射:getName
getName方法可以打印出类类型的类名称。
publicclassTest2{publicstaticvoidmain(String[]args){Classc1=String.class;//String类的类类型Classc2=void.class;System.out.println(c1.getName());System.out.println(c2.getName());}}
成员变量反射
publicclassTestUtil{publicstaticvoidprintFieldMessage(Objectobj){Classc=obj.getClass();//Field[]fs=c.getFields();}
getFields()方法获取的所有的public的成员变量的信息。和方法的反射那里public的成员变量,也有一个获取所有自己声明的成员变量的信息:Field[] fs = c.getDeclaredFields(),然后遍历得到的结果如下:
for(Fieldfield:fs){//得到成员变量的类型的类类型ClassfieldType=field.getType();StringtypeName=fieldType.getName();//得到成员变量的名称StringfieldName=field.getName();System.out.println(typeName+""+fieldName);}
构造函数的反射
publicstaticvoidTest(Objectobj){Classc=obj.getClass();/**java.lang.Constructor中封装了构造函数的信息,它有两个方法:*getConstructors()方法获取所有的public的构造函数*getDeclaredConstructors()方法得到所有的自己声明的构造函数*///Constructor[]cs=c.getConstructors();Constructor[]cs=c.getDeclaredConstructors();for(Constructorconstructor:cs){System.out.print(constructor.getName()+"(");//获取构造函数的参数列表->参数列表的类类型Class[]paramTypes=constructor.getParameterTypes();for(Classclass1:paramTypes){System.out.print(class1.getName()+",");}System.out.println(")");}}
总结
反射在实际编程中应用并不多,但是很多设计都与反射机制有关,比如:动态代理机制,JDBC连接数据库, Spring/Hibernate框架(实际上是因为使用了动态代理,所以才和反射机制有关)。