黑马程序员----Java中反射机制的总结

来源:互联网 发布:qr是什么软件 编辑:程序博客网 时间:2024/05/18 00:05

------Java培训、IOS培训、.NET培训、期待与您交流!------

反射,故名思意就是和正常的方向相反。正常情况下,我们都是在基于已经了解类中所有成员信息例如成员域,成员方法等等信息后再调用这些成员,而反射则相反,则是通过这些成员信息获取类的信息,或者通过类的一部分信息获取类所有成员的信息。

在Java中,如果不知道某个对象的确切类型,RTTI可以告诉你,但是这个类型在编译时必须一直,乍看起来,这根本就不是个限制,但是如果获取了一个并不在本地程序中存在的类对象的引用,那么编译时就无法知道这个对象所属的类,这种情况下使用反射机制就非常便捷。对于RTTI,运行时类型检查而言,是在编译时打开和检查.class文件,而对于反射而言,.class文件在编译时无法获取,所以是在运行时打开和检查.class文件。

在Java中的任何类都属于同一个事物,描述这类事物的名称就叫做Class类,该类对应的是类在内存中的字节码,每当创建一个类时,都会创建一个Class对象,被保存在同名的.class文件中。而提供类中方法信息的类是Method,提供类中域信息的类是Field,提供类中构造方法信息的类是Constructor。这些类构成了反射的基础.

Class类又是这些反射类中的基石,例如无法直接从Method实例对象推断出该类对应的Constuctor对象信息,而必须经过Class类中转,先获得该Method对象的Class类信息,然后再去推断Constructor'信息,获得Class对象的方法有:每个类对象从Object类中继承了getClass()方法。例如一个String st="hello".那么就可以调用st.getClass()来取得类对象。

也可以用String.class来调用Class对象的引用,即类字面常量。或者用Class.forName(String name)方法来返回一个Class对象.另外关于Class类对象还有一个叫做类加载器的类ClassLoader类,ClassLoader类是加载类的类,所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类,这也间接证明构造器也是类的静态方法。而类加载器就是首先检查这个类的Class对象是否已经被加载,如果尚未加载,默认的类加载器就会根据类名查找.class文件因此可以用forName()方法还有一个接受ClassLoader类的forName(String name,boolean initialize,ClassLoader loader)方法,initialize表示该类是否必须被初始化,例如forName(String.class)等效于forName(String.class,true,this.getClass().getClassLoader()).

Class类中主要获得其他反射类的方法有

和Method类相关的:                      

public Method[] getMethods()方法:返回此Class对象所表示的类或接口中所有的公共成员方法Method数组。

public Method getMethod(String name.Class<?>...param)返回该类中一个名字为name,参数为Class类数组param的公共方法。如果param为null,则表示没有参数。

public Method[] getDeclaredMethods():返回此Class对象所表示的类或接口中所有的已经声明的Mehod数组,其和getMethods()方法的区别在于返回数组包括private和package方法,但不包括继承的方法.

public Method getDeclaredMethod(String name.Class<?>...param)返回该类中一个名字为name,参数为param的方法,该方法可以不是public的。

和Constructor类相关的:

public Constructor[] getConstructors()返回该Class对象表示的类中所有的公共构造方法的Construtor类数组。

public Constructor getConstructor(Class<?>...param)返回一个Constructor对象代表该Class类对象表示的类中参数为param数组中Class对象表示的类的一个公共构造方法。

Public Constructor[] getDeclaredConstructors()返回该Class对象表示的类中的所有构造方法的Constructor数组,包括public的构造方法。

public Constructor getDeclaredConstructor(Class<?>...param)返回Class类中一个Constructor参数为param中Class类对象表示的类。

和Field类相关的:

public Fileds[] getFields()返回该Class类对象表示的类中所有的公共字段Field数组。

public Fileds[] getDeclaredFields()返回该Class类对象表示的类中所有的字段Field数组,包括非public的Field。

public Field getField(String name)返回该类中引用名称为name的public字段。

public Field getDeclaredField(String name)返回该类中引用名称为name的字段,该字段不必是public。

虽然Class类对象不能使用运行时的instanceof,但是可以用等价的动态isinstance判断该Class对象是否与对象兼容。

也可以用isArray判断该Class对象是不是表示一个数组,值得一提的是,所有类型的数组,不管是Integer[]还是String[]的Class对象都相同。

newInstance()方法可以用来创建该对象的一个新实例,当然前提是该Class对象表示的类有默认的null构造方法以及该构造方法可以访问。

Construcotr类

Construcotr类中的重要方法就是newInstance(Object... param)该方法返回一个参数为Object数组的类新实例。

例如Constructor c=String.class.getConstructor(StringBuffer.class)

那么就可以用c.newInstance(new Stringbuffer("hello"))新建一个String对象。该参数必须是c构造方法中的Class实例对象。

Field类

Field对象的实例表示某个特定类中的某个特定的成员变量,所以其值是不确定的。可以用getType()方法返回其代表域类型的Class对象以及getDeclaringClass()方法返回声明该域的类的Class对象.

例如class Test

{

public int x;

private int y;

public Test(int x,int y){

this.x=x;

this.y=y;

}

Test t=new Test(3,6);

Field f=t.getClass().getField("x");

那么f只是代表Test类中的这个x变量,在t这个对象中是3,需要用f.get(t)来取回其中的值。

所以对于Field类有getByte(Object o),getInt(Object o),getLong(Object o),getDouble(Object o),getFloat(Object o),getShort(Object o),getChar(Object o),getBoolean(Object o)来取特定对象实例中该字段的8种基本类型数据的值以及通用的get(Object  o)获取该字段的值。

也有setByte(Object o,byte b),setInt(Object o,int i),setLong(Object o,long l),setDouble(Object o,double d),setFloat(Object o,float f),setShort(Object o.short s),setChar(Object o,char c),setBoolean(Object o,boolean bo)8中方法设置某个特定对象实例中该字段的8种基本类型的值,

或者通用的set(Object o,Object value)来设置对象o上该字段的值.

然而对于私有变量y,用Field fi=t.getClass().getDeclaredFiled("y")后,依然不能访问,因为fi是private的,那么这个时候需要用到权限控制额setAccessible(fi)使其可用。

Method类:

方法有3个关键区别的要素:名字,返回类型,形参类型,分别用getName(),getReturnType(),getTypeParameters()方法实现。

Method类中最关键的方法就是invoke(Object o,Object... args)了,其中o表示要调用该方法的对象,而args表示形参。如果方法是静态的,那么o可以为null,如果没有形参,那么args也可以为null。

例如Method m=String.class.getMethod("equals");

String s=“world";

那么就可以用m.invoke(s,"haha")来调用s的m方法。

反射是JAVA中一个强大的机制,也是很灵活的机制,但是也很复杂。上述只是一些基本的介绍,真正深入需要多熟练,何时使用,如何使用都需要更加缜密的思考。

0 0