《JAVA核心技术卷I》第五章反射笔记
JAVA中能够分析类能力的程序称为反射,可以用来:
1、在运行时分析类的能力
2、在运行时查看对象
3、实现通用的数组操作代码
4、利用Method对象
在程序运行期间,JAVA运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类,虚拟机利用运行时类型信息选择相应的方法执行。保存这些信息的类被称为Class。Object类中的getClass()方法将会返回一个Class类型的实例。
Class的getName()方法可以返回类的名字,如果类在一个包里,包的名字也作为类名的一部分;
Random generator = new Random();
Class c1 = generator.getClass();
String name = c1.getName;
还可以调用静态方法forName()获得类名对应的Class对象
String className = "java.util.Random";
Class c1 = Class.forName(className);
只有在className是类名或接口名时才能够执行,否则,forName方法将抛出一个checkedexception(已检查异常)。
如果T是任意的JAVA类型(或void关键字),T.class将代表匹配的类对象
Class c1 = Random.class;
Class c2 = int.class;
Class c3 = Double[].class;
注意:一个Class对象表示一个类型,而这个类型未必一定是一种类。如int不是类,但int.class是一个Class类型的对象。Class类是一个泛型类。
虚拟机为每个类型管理一个Class对象,因此可以用 == 运算符实现两个类对象的比较。
newInstance()方法可以用来动态地创建一个类的实例,非常有用。
利用反射分析类的能力
在java.lang.reflect包中有三个类Field、Method和Constructor分别用于描述类的域、方法和构造器。三个类都有getName方法来返回项目名称。
一个可以分析传入类名对应类的小例子:
package reflection;
import java.lang.reflect.*;
import java.util.*;
public class ReflectionTest {
public static void main(String[] args) {
// TODO 自动生成的方法存根
String name;
if(args.length>0)
name=args[0];
else{
Scanner in=new Scanner(System.in);
System.out.println("Enter class name(e.g.java.util.Date):");
name=in.next();
}
try {
Class class1=Class.forName(name);
Class superClass=class1.getSuperclass();
String modifiers=Modifier.toString(class1.getModifiers());
if(modifiers.length()>0)
System.out.println(modifiers + " ");
if(superClass != null && superClass != Object.class)
System.out.println(" extends " + superClass.getName());
System.out.println("\n{\n");
//打印所有类的构造器
printConstructor(class1);
System.out.println();
//打印所有类的方法
printMethods(class1);
System.out.println();
//打印所有类的域
printFields(class1);
System.out.println("}");
} catch (ClassNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
}
System.exit(0);
}
//打印类所有的域
private static void printFields(Class class1) {
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
Class type = field.getType();
String name = field.getName();
System.out.print(" ");
String modifiers = Modifier.toString(field.getModifiers());
if(modifiers.length()>0)
System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + name + ";");
}
}
//打印类所有的方法
private static void printMethods(Class class1) {
Method[] methods=class1.getDeclaredMethods();
for (Method method : methods) {
Class reType = method.getReturnType();
String name = method.getName();
System.out.print(" ");
//打印修饰符,返回类型和方法名
String modifiers = Modifier.toString(method.getModifiers());
if(modifiers.length()>0)
System.out.print(modifiers + " ");
System.out.print(reType.getName() + " " + name + "(");
//打印参数类型
Class[] paramType = method.getParameterTypes();
for(int j = 0; j < paramType.length; j++){
if(j > 0)
System.out.print(", ");
System.out.print(paramType[j].getName());
}
System.out.println(");");
}
}
//打印类所有的构造器
public static void printConstructor(Class class1) {
Constructor[] constructors=class1.getDeclaredConstructors();
for(Constructor constructor : constructors){
String name=constructor.getName();
System.out.print(" ");
String modifiers = Modifier.toString(constructor.getModifiers());
if(modifiers.length()>0)
System.out.print(modifiers + " ");
System.out.print(name + "(");
//打印参数类型
Class[] paramTypes = constructor.getParameterTypes();
for(int j = 0; j < paramTypes.length; j++){
if(j>0)
System.out.print(", ");
System.out.print
(paramTypes[j].getName());
}
System.out.println(");");
}
}
}
就分析这个小例子来测试,得到如下结果:
注:
getFields()和getDeclaredFields():
getFields方法将返回一个包含Field对象的数组,这些对象记录了这个类或其超类的公有域。getDeclaredFields方法也将返回包含Field对象的数组,这些对象记录了这个类的全部域。如果类中没有域,或者Class对象描述的是基本类型或数组类型,这些方法将返回一个长度为0的数组。
getMethod()和getDeclaredMethod():
返回包含Method对象的数组:getMethod将返回所有的公有方法,包括从超类继承来的公有方法;getDeclaredMethods返回这个类或接口的全部方法,但不包括由超类继承了的方法。
getConstructor()和getDeclaredConstructors():
返回包含Constructor对象的数组,其中包含了Class对象所描述的类的所有公有构造器(getConstructors)或所有构造器(getDeclaredConstructors)。
getModifiers():
返回一个用于描述构造器、方法或域的修饰符的整数数值(public、static等)。使用Modifier类中的这个方法可以分析这个返回值 (isPublic、isPrivate等)。
getParameterTypes():
返回一个用于描述参数类型的Class对象数组。
getReturnType():
返回一个用于描述返回类型的Class对象。
Modifier.toString(int modifiers):
返回对应modifiers中位设置的修饰符的字符串表示。
在运行时使用反射分析对象
setAccessible(boolean flag):
为反射对象设置可访问标志。flag为true表面屏蔽Java语言的访问检查,使得对象的私有属性也可以被查询和设置。
get(Object obj):
返回obj对象中用Field对象表示的域值。
set(Obeject obj,Object newValue):
用一个新值设置Obk对象中的Field对象表示的域。
invoke(Object implicitParameter,Object[] explicitParamenters):
调用这个对象所描述的方法,传递给定参数,并返回方法的返回值。对于静态方法,把null作为隐式参数传递。在使用包装器传递基本类型的值时,基本类型的返回值必须是未包装的。