3.Members
3.1Fields
3.2Methods
翻译源:Java toturial 反射篇
域是关联值的类、接口、枚举。
java.lang.reflect.Field中的方法可以检索域的信息,eg:名称、类型、修饰符、注解。有些方法还支持动态访问修改域值。
获取域名
String s = f.getName();
获取指定域
Field f = c.getField(fn);
Field f = c.getDeclaredField(fn);
获取所有域
Field[] flds = = c.getDeclaredFields();
Field[] fields = c.getFields();
获取域类型
Class c = f.getType();
note:返回表示Field对象f表示的域的类型的Class对象。
ps:如果类型为泛型,会受到类型擦除的影响。
Type t = f.getGenericType();
note:返回表示Field对象f表示的域的类性的Type对象。
ps:会从class文件的签名属性中读取类型信息,所以不会受到泛型的类型擦除机制的影响。
检索解析域修饰符
获取修饰符
int foundMods = f.getModifiers();
note:获取域f的修饰符集合。
ps:修饰符在java中的表现形式是Modifier中定义的静态常量,修饰符集合就是这些十六位int常量|操作之后的结果。
ps:可以使用Modifier解析这个int,获取域的所有修饰符信息。
判断域是否为合成域
boolean b = f.isSynthetic();
ps:合成域的意思是java编译器自动引入的域。
ps:内部类会自动引入合成域this$0,用于指向外部类。
ps:枚举类会自动引入合成域ENUM$VALUES。
ps:合成域由编译器决定,所以不同编译器可能会产生名称不同的合成域。
ps:合成域可以通过getDeclaredFields()获取。
判断域是否为枚举类型元素
boolean b = f.isEnumConstant();
ps:枚举类中的域皆是枚举类型元素。
判断域的修饰符是否包含给定修饰符
int searchMods = 0x0;
searchMods |= Modifier.PUBLIC;
int foundMods = f.getModifiers();
if((foundMods & searchMods) == searchMods) {
...
}
note:如果域f为public,则执行if语句块。
Field实现了AnnotatedElement接口,所以可以获取持有的注解。
获取设置域值
获取原始类型域的值
long l = f.getLong(obj);
note:获取对象obj的long类型f域值l。
ps:getInt、getDouble、getFloat、getShort、getLong、getByte、getChar、getBoolean。
获取引用类型域的值
Object o = f.get(ft);
设置原始类型域的值
f.setLong(ftt, 33333);
note:将ftt对象的f域设置为33333,f域的类型为long。
ps:setInt、setDouble、setFloat、setShort、setLong、setByte、setChar、setBoolean。
设置引用类型域的值
f.set(ft, sss);
note:将ft对象的f域设置为对象sss,f域的类型为引用类型。
不能使用反射来修改final常量。
反射代码将方法选择限定在一个特定类之中,而不考虑它的父类。
获取方法名
String s = m.getName();
获取指定方法
m = c.getMethod("run", int.class);
m = c.getDeclaredMethod("run", int.class);
ps:如果获取的方法的参数使用了泛型,使用java.lang.Object。
获取所有方法
Method[] allMethods = c.getMethods();
Method[] allMethods = c.getDeclaredMethods();
获取方法类型信息
获取方法名
String ss = m.toGenericString();
获取方法返回值类型
Class c = m.getReturnType();
Type t = m.getGenericReturnType();
ps:前者在遭遇泛型时,返回Object的Class,后者返回表示泛型参数的Type。
获取方法参数类型列表
Class>[] mty = m.getParameterTypes();
Type[] gty = m.getGenericParameterTypes();
ps:前者在遭遇泛型时,返回Object的Class,后者返回表示泛型参数的Type。
ps:如果获取的参数为可变参数,此参数返回一个组件类型为参数类型的数组的Class。
获取抛出异常列表
Class>[] ety = m.getExceptionTypes();
Type[] gety = m.getGenericExceptionTypes();
获取方法参数名
字节码文件默认不存储参数名称。
使用javac编译源代码时,使用-parameters选项可以将参数名称存入.class文件中,供反射机制获取。
使用java.lang.reflect.Parameter作为接口操作参数。
获取参数列表
Parameter[] ps = m.getParameters();
获取参数名称
String s = p.getName();
ps:如果没有设置javac的-parameters选项,根据参数列表顺序返回arg0、args1……
获取参数类型
Class c = p.getType();
获取参数修饰符
int m = p.getModifiers();
ps:可以使用Modifier.toString(),将得到的int表示的参数修饰符集合转变为可读字符串。
判断参数是否有名称
boolean b = p.isNamePresent();
判断参数是否为隐式参数
boolean b = p.isImplicit();
ps:java编译器会为内部类创建一个包含外部类引用参数的默认构造方法,此参数为隐式参数,此隐式参数为final与implicit。
判断参数是否为合成参数
boolean b = p.isSynthetic();
ps:编译器引入的没有在源代码中显式或隐式声明的结构,除了类初始化方法,都属于合成。
ps:Enum结构,默认由编译器创建构造器、values()、valueOf(String name)。
ps:合成方法内的参数皆是合成参数。
检索分析方法修饰符
获取方法修饰符
int mod = m.getModifiers();
判断方法是否含有变参
boolean b = m.isVarArgs();
note:包含返回true。
判断方法是否为桥接方法
boolean b = m.isBridge();
note:桥接方法返回true。
ps:桥接方法是,编译器在是实现泛型接口的类中,创建的以Object作为参数类型,并且调用实现类中的方法的中介方法。
ps:桥接方法就是一种合成方法。
判断方法是否为合成方法
boolean b = m.isSynthetic();
Method实现了AnnotatedElement接口,可以以此获取Method持有的注解。
调用方法
反射提供了调用类方法的API。
通常情况下,当不能类实例转化为需要的类型时,反射是调用方法的唯一途径。
反射调用方法
m.invoke(obj, null);
note:调用对象的Method对象m代表的无参方法。
ps:调用静态方法时,第一个参数传null。
ps:调用无参函数时,第一个参数之后的参数可以不传。
ps:方法的参数数量不定时,获取方法时使用数组类型的Class锁定方法,调用时传入数组。
ps:调用的方法如果为private,将会抛出异常。
ps:使用AccessibleObject.setAccessible()设置true,强制访问private。
获取反射调用方法抛出的异常
Throwable t = e.getCause();
ps:反射调用的方法抛出的异常会被反射框架的InvocationTargetException包装,通过getCause()方法可以获取原异常。
检验当前class与指定class是否相同,或是其父类
boolean b = YU.class.isAssignableFrom(TY.class);
note:检测YU是否与TY相同,或者YU为TY的父类。如果是,返回true。
ps:判断调用方法的Class代表的类型对象是否能给指定类型进行赋值,原理是父类对象可以让子类引用。