Java反射机制及其Class类浅析
首先谈谈什么是反射,这所说的反射是特制在编程语言中的反射,其官方解释如下:
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
其作用如下:
1.加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
2.了解包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
3.了解函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。
4.调用特定的构造函数。
5.了解方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信 息(如 abstract 或 virtual)等。
6.了解字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。
7.了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
8.了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
9.了解参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。
我们可以清楚的看到,其实反射这个功能所拥有的功能如其字面的的含义,即“反射”关于对象的自身的属性和行为的描述。用比较科学的话来说就是自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),然后其他程序根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
在Java中这种反射机制得到的很好的实现,其将其封装到一个Class类中:
我们可以看看JDK文档,简单的了解一下这个类。
public final class Class<T>extends Objectimplements Serializable, GenericDeclaration, Type, AnnotatedElement
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
一些重要的函数
<A extends Annotation> A getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
Annotation[] getAnnotations()
返回此元素上存在的所有注释。
String getCanonicalName()
返回《Java Language Specification》中所定义的基础类的规范化名称。
Class[] getClasses()
返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口,包括从超类和公共类继承的以及通过该类声明的公共类和接口成员。
ClassLoader getClassLoader()
返回该类的类加载器。
Class<?> getComponentType()
返回表示数组组件类型的 Class。
Constructor<T> getConstructor(Class... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
Constructor[] getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。
Class[] getDeclaredClasses()
返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口,包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口。
Constructor<T> getDeclaredConstructor(Class... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
Constructor[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
Field[] getDeclaredFields()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段,包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。
Method getDeclaredMethod(String name, Class... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Class<?> getDeclaringClass()
如果此 Class 对象所表示的类或接口是另一个类的成员,则返回的 Class 对象表示该对象的声明类。
Class<?> getEnclosingClass()
返回基础类的立即封闭类。
Constructor<?> getEnclosingConstructor()
如果该 Class 对象表示构造方法中的一个本地或匿名类,则返回 Constructor 对象,它表示基础类的立即封闭构造方法。
Method getEnclosingMethod()
如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method 对象,它表示基础类的立即封闭方法。
T[] getEnumConstants()
如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null。
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field[] getFields()
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
Type[] getGenericInterfaces()
返回表示某些接口的 Type,这些接口由此对象所表示的类或接口直接实现。
Type getGenericSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。
Class[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
Method getMethod(String name, Class... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
int getModifiers()
返回此类或接口以整数编码的 Java 语言修饰符。
String getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
Package getPackage()
获取此类的包。
java.security.ProtectionDomain getProtectionDomain()
返回该类的 ProtectionDomain。
java.net.URL getResource(String name)
查找带有给定名称的资源。
InputStream getResourceAsStream(String name)
查找具有给定名称的资源。
Object[] getSigners()
获取此类的标记。
String getSimpleName()
返回源代码中给出的基础类的简称。
Class<? super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
TypeVariable<Class<T>>[] getTypeParameters()
按声明顺序返回 TypeVariable 对象的一个数组,这些对象表示用此 GenericDeclaration 对象所表示的常规声明来声明的类型变量。
boolean isAnnotation()
如果此 Class 对象表示一个注释类型则返回 true。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
boolean isAnonymousClass()
当且仅当基础类是匿名类时返回 true。
boolean isArray()
判定此 Class 对象是否表示一个数组类。
boolean isAssignableFrom(Class<?> cls)
判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
boolean isEnum()
当且仅当该类声明为源代码中的枚举时返回 true。
boolean isInstance(Object obj)
判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
boolean isInterface()
判定指定的 Class 对象是否表示一个接口。
boolean isLocalClass()
当且仅当基础类是本地类时返回 true。
boolean isMemberClass()
当且仅当基础类是成员类时返回 true。
boolean isPrimitive()
判定指定的 Class 对象是否表示一个基本类型。
boolean isSynthetic()
如果此类是复合类,则返回 true,否则 false。
从JKD中我们可以看到,其中get开头的函数比较多,其实我们只需要知道,该类型可以得到你所需要的类型的所有信息即可,然后就可以查询函数。其类型分别为:Field、Constructor、Method、Class、Object。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
最后通过如下的例子来简单的说明其用法:
//需要反射的类 One.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class One implements ActionListener
{
private int a = 3 ;
private String name ="One";
public Integer b = new Integer( 4 );
public double c = 1.23;
public One(){}
public One( int id,String name){}
public int OneFunction( int id,String name)
{
return 0 ;
}
public double TwoFunction(double C)
{
return C;
}
@Override
public void actionPerformed(ActionEvent e){}
}
//运行类 Work.java
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Work {
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
One one = new One();
Class temp = one.getClass();
String className = temp.getName();
System.out.println("该类名为: "+className);
int i,j,k;
try
{
System.out.println("反射类中所有公有的属性" );
Field[] Ca =temp.getFields();
for ( i= 0 ;i<Ca.length;i++)
{
Class cl = Ca[i].getType();
System.out.println("公共属性: " +cl);
}
System.out.println("反射类中所有的属性" );
Field[] Aa= temp.getDeclaredFields();
for ( i=0;i<Aa.length;i++)
{
Class cl = Aa[i].getType();
System.out.println("所有属性: " +cl);
}
System.out.println("反射类中私有属性的值" );
Field f = temp.getDeclaredField("a" );
f.setAccessible(true );
Integer I = (Integer)f.get(one);
System.out.println(I);
System.out.println("反射类中的构造函数" );
Constructor[] theConstructors = temp.getConstructors();
for ( k= 0 ; k<theConstructors.length; k++)
{
Class[] parameterTypes = theConstructors[k].getParameterTypes();
System.out.print(className + "(" );
for ( j= 0 ; j<parameterTypes.length; j++)
System.out.print(parameterTypes[j].getName() + " " );
System.out.println(")" );
}
System.out.println("反射类中的接口父类");
Class[] theInterfaces = temp.getInterfaces();
for ( j= 0 ; j<theInterfaces.length; j++)
System.out.println(theInterfaces[j].getName());
System.out.println("反射类中的接口父类");
Class theSuperclass = temp.getSuperclass();
System.out.println(theSuperclass.getName());
System.out.println("反射类中的函数");
Method[] m = temp.getMethods();
for ( k= 0 ; k<m.length; k++)
{
//System.out.println("函数的返回值");
System.out.print(m[k].getReturnType().getName());
//System.out.println("函数名");
System.out.print(" " +m[k].getName()+ "(" );
//System.out.println("函数参数");
Class[] parameterTypes = m[k].getParameterTypes();
for ( j= 0 ; j<parameterTypes.length; j++)
{
System.out.print(parameterTypes[j].getName());
if (parameterTypes.length>j+ 1 )
{
System.out.print("," );
}
}
System.out.println(")" );
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
//结果
该类名为: classeg.One
反射类中所有公有的属性
公共属性: class java.lang.Integer
公共属性: double
反射类中所有的属性
所有属性: int
所有属性: class java.lang.String
所有属性: class java.lang.Integer
所有属性: double
反射类中私有属性的值
3
反射类中的构造函数
classeg.One()
classeg.One(int java.lang.String )
反射类中的接口父类
java.awt.event.ActionListener
反射类中的接口父类
java.lang.Object
反射类中的函数
int OneFunction(int,java.lang.String)
double TwoFunction(double)
void actionPerformed(java.awt.event.ActionEvent)
void wait()
void wait(long,int)
void wait(long)
int hashCode()
java.lang.Class getClass()
boolean equals(java.lang.Object)
java.lang.String toString()
void notify()
void notifyAll()
总结:
其实对于一般简单的Java程序而言,这种反射的功能是没有什么必要的。但当编写复杂的程序时,反射的的功能有时可以完成一些不可思议的任务。
参考文章:
Java API 文档
http://blog.csdn.net/cnham/article/details/3086038
http://baike.baidu.com/view/77128.htm#sub8468663