反射是什么?
在运行状态中,获取一个类的所有属性和方法。这种动态获取信息以及调用对象的方法的功能。
使用反射机制的一些框架?
Retrofit中的注解功能、EventBus,动态生成框架 Gson。
使用反射技术查看类信息
获取Class对象的三种方法
使用Object.getClass方法
如果我们能知道一个对象,可以通过调用这个对象的getClass方法获得一个Class对象。
例如:
Person person = new Person();
Class extends Person> aClass = person.getClass();
System.out.println(aClass.getName());
这时候就会打印这个对象的全包名,aClass中还有其他信息。
使用.class方法
Class extends Person> aClass = Person.class;
System.out.println(aClass.getName());
System.out.println(int.class);
如果没有获取某个类的对象,无法使用getClass方法,可以直接在类名加上.class来获取,这种方式可以用于基本数据类型。
使用Class.forName()方法
这个方法要使用一个类的完整路径,就可以使用Class.forName("类的完整路径")来得到相应的Class。
try {
Class mclass1 = Class.forName("main.fanshe.Person");
System.out.println(mclass1.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
注意:使用Class的newInstance()方法来创建对应类的实例,需要有默认的构造器,执行newInstance()方法实际上市利用默认构造器来创建该类的实例。
Class mclass1 = Class.forName("main.fanshe.Person");
Object o = mclass1.newInstance();
通过反射获取成员变量
常用获取成员属性的方法
Field[] declaredFields = mclass1.getDeclaredFields();//获取Class对象的所有属性
Field[] fields = mclass1.getFields();//获取class对象的public属性
Field ageField = mclass1.getDeclaredField("age");//获取class指定属性
Field desFiedl = mclass1.getField("name");//获取class指定的public属性
如果获取到属性可以用过set方法进行修改例如:
Field ageField = mclass1.getDeclaredField("age");//获取class指定属性
ageField.setInt(o,22);
如果这个属性是用private修饰的话,这样写的话代码会报错
java.lang.IllegalAccessException: Class main.fanshe.Main can not access a member of class main.fanshe.Person with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.setInt(Field.java:946)
at main.fanshe.Main.main(Main.java:50)
这时我们要添加 ageField.setAccessible(true);这个方法来声明这个变量是可以访问的就没问题了,但是使用这个方法也可能会导致些其他问题,例如
在运行时虽然你通过反射修改了变量 a 的值,但其他部分可能还在使用原来的值。
通过反射获取成员方法
Method[] methods = mclass1.getDeclaredMethods();//获取class对象的所有声明方法
Method[] allMethods = mclass1.getMethods();//获取class对象的所有public声明方法
Method method = mclass1.getMethod("getAge");//根据方法名返回方法
Method method2 = mclass1.getMethod("getAge",String.class);//根据带指定形参列表的public方法
System.out.println(method.toString());
可以通过method.invoke(o);这个方法调用反射到的方法。
总结
反射还有好多其他方法,可以通过查询API获知,例如获取构造方法等,功能貌似还是比较强大的,但是反射的一些操作可能会引起性能消耗,例如修改某个成员变量的时候,需要引发验证访问权限等额外操作等。所以使用反射的时候也许要考虑下性能方面的问题。