反射,在解耦业务的框架中有广泛应用。另外还有注解,注解处理器以及泛型。他们组成了解耦框架们的四驾马车。
getConstructors和getDeclaredConstructors区别
getConstructors获取自身的public的构造方法。
getDeclaredConstructors获取自身的所有构造方法,无论是public, protect还是private, default.
两个方法都自能获取自身的构造方法,不能获取继承的构造方法。
getMethods和getDeclaredMethods区别
getMethods获取外部可访问的方法,也就是说不仅返回自身的public方法,还包含继承的public方法。
getDeclaredMethods获取所有自身的方法,无论是public, protect还是private, default.只能返回自身的方法。无法获取继承的任何方法。
Test testRe = new TestRe();
Class temp = testRe.getClass();
String className = temp.getName();
try {
Constructor[] constructors = temp.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++) {
//获取方法的修饰符,也就是public,protecth还是privated的
int mod = constructors[i].getModifiers();
//把修饰符转成string
System.out.println(Modifier.toString(mod) + " " + className+"(");
//获取方法的参数数组。
Class[] parameterTypes = constructors[i].getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
//打印参数名。
System.out.println(parameterTypes[j].getName());
if (parameterTypes.length > j + 1) {
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
getModifiers()
返回修饰符号。从命名就可以看出其实是个数组。通过&来判断有无。
不仅包括public, protect, private。
在Modifier类中的toString方法中,可以看到所有的修饰符:
public static String toString(int mod) {
StringBuilder sb = new StringBuilder();
int len;
if ((mod & PUBLIC) != 0) sb.append("public ");
if ((mod & PROTECTED) != 0) sb.append("protected ");
if ((mod & PRIVATE) != 0) sb.append("private ");
/* Canonical order */
if ((mod & ABSTRACT) != 0) sb.append("abstract ");
if ((mod & STATIC) != 0) sb.append("static ");
if ((mod & FINAL) != 0) sb.append("final ");
if ((mod & TRANSIENT) != 0) sb.append("transient ");
if ((mod & VOLATILE) != 0) sb.append("volatile ");
if ((mod & SYNCHRONIZED) != 0) sb.append("synchronized ");
if ((mod & NATIVE) != 0) sb.append("native ");
if ((mod & STRICT) != 0) sb.append("strictfp ");
if ((mod & INTERFACE) != 0) sb.append("interface ");
if ((len = sb.length()) > 0) /* trim trailing space */
return sb.toString().substring(0, len-1);
return "";
}
getParameterTypes
返回方法中的参数列表。
getFields和getDeclareFields区别
getFields 获取指定的 public 字段 父类中的公有字段也能够获取到
getDeclareFields获取全部的 private、protected、default、public 的字段,, 但是只能取到该类自身定义的字段,从父类中继承的字段不能够获取到。
setAccessible
设置该字段是否可被访问, true表示可以访问该字段
反射的作用
根据class或者字符串生成实体对象, 再调用方法。以下是实际使用。
Test testRe = new TestRe();
Class temp = testRe.getClass();
//也可以通过Class.forName()方法获取class实例
//try {
// temp = Class.forName("com.com.nero.monalisa.activity.TestRe");
// } catch (ClassNotFoundException e) {
e.printStackTrace();
// }
String className = temp.getName();
try {
//获取无参构造方法
Constructor constructor1 = temp.getConstructor();
Class[] classes = new Class[]{int.class, String.class};
//获取有参构造方法
Constructor constructor2 = temp.getConstructor(classes);
//实例化无参对象
TestRe testRe1 = (TestRe) constructor1.newInstance();
//实例化有参对象
TestRe testRe2 = (TestRe) constructor2.newInstance(1, "alan");
//调用public方法
Method publicMethod = temp.getMethod("doPublicSomeThing", int.class, String.class);
publicMethod.invoke(testRe2, 2, "gong");
//调用private方法
Method privateMethod = temp.getDeclaredMethod("doPrivateThing", int.class, String.class);
//设置可以访问private方法
privateMethod.setAccessible(true);
privateMethod.invoke(testRe2, 3, "lindi");
//调用private的静态方法
Method privateStaticMethod = temp.getDeclaredMethod("work");
privateStaticMethod.setAccessible(true);
privateStaticMethod.invoke(null); //由于是静态的,所以不需要本对象传入。
//获取私有字段,并且修改值
Field field = temp.getDeclaredField("b");
field.setAccessible(true);
String value = (String) field.get(testRe2);
field.set(testRe2, "alan gong");
//获取静态私有字段,并且修改值。 这次修改是对全局有效的。
Field privateStaticField = temp.getDeclaredField("c");
privateStaticField.setAccessible(true);
Object value1 = privateStaticField.get(null);
privateStaticField.set(value1, "lindi gong");
} catch (Exception e) {
e.printStackTrace();
}
泛型与反射
关于Java泛型,很多人都有一个误解,认为Java代码在编译时会擦除泛型的类型,从而在运行时导致没法访问其类型,这其实并不完全正确,因为有一部分泛型信息是可以在运行时动态获取的,这部分信息基本能够满足我们日常开发中的大多数场景。
这部分信息都存在Class类,Method类里面。可以用反射来获取部分泛型参数的类型信息。其实是非常有用的一个功能,比如在一些json工具的开源包里面,可以对Java里面泛型的各种List,List等类型做正确识别。
另外有必要知道以下两组的作用和区别:
getSuperclass和getGenericSuperclass区别
getSuperclass 返回直接继承的父类(由于编译擦除,没有显示泛型参数)
getGenericSuperclass 返回直接继承的父类(包含泛型参数)
//此段代码是在父类调用的。
Class clazz = this.getClass(); //this是子类对象。
Type type = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType)type;
Type[] types = param.getActualTypeArguments(); //由此得出泛型的具体类数组,如果有多余一个类型
getInterfaces和getGenericInterface区别
getInterfaces 返回直接实现的接口(由于编译擦除,没有显示泛型参数)
getGenericInterface 返回直接实现的接口(包含泛型参数)
反射还有一个特别的应用。替换系统单例对象的值。赋值成动态代理的对象。这样就可以起到拦截系统对象的目的了。
android插件化就是这么玩的。
最后有一个简化反射的封装库jOOR
mport static org.joor.Reflect.*;
String world = on("java.lang.String") // Like Class.forName()
.create("Hello World") // Call most specific matching constructor
.call("substring", 6) // Call most specific matching substring() method
.call("toString") // Call toString()
.get(); // Get the wrapped object, in this case a String