前言:在前面EventBus的源码分析过程中,在进行注册过程的源码中关于获取类的信息和注解的方法信息是靠反射实现的,最终相应事件调用的执行方法也是靠反射实现的。所以今天的这篇文章是单独拿出来讲反射机制的,希望对想了解反射知识的伙伴可以有所帮助。
为什么需要反射?
Android 系统在设计的时候,出于安全和架构的考虑,利用了 Java 权限相关的东西(private,package等等,以及 @hide 这个注解)使得我们无法访问某些字段,或者方法。但在实际开发过程中,这些隐藏的字段或者方法却能提供给我们非常想要的特性。
在这种矛盾的情况下,反射就能满足我们的需求,它像是打开隐藏关卡的一把钥匙。所以我们需要使用反射!!!
反射优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能。
反射缺点:
(1)使用反射的性能较低 。
(2)使用反射相对来说不安全 。
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性 。
反射简介
Java 程序的运行需要相应的环境(Java Runtime Environment), 而这其中最有名的就是 JVM,JVM 提供了动态运行字节码的能力,除了 JVM 帮我们做链接、加载字节码相关的事情外,也通过反射提供给我们动态修改的能力。反射使得我们能够在运行时,不知道类名、方法名的情况下查看其中的接口、方法和字段等信息,另一方面,也可以动态调用方法、新建对象,甚至篡改字段值。
总结起来就是,反射提供了一种与 Class 文件进行动态交互的机制。
反射机制提供的功能
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时判断任意一个类所具有的成员变量和方法;
- 在运行时调用任意一个对象的方法;
java Reflection API
- Class类:代表一个类,位于java.lang包下
- Field类:代表类的成员变量(成员变量也称为类的属性)
- Method类:代表类的方法
- Constructor类:代表类的构造方法
- Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Class 类简介
Class 类十分特殊,它没有共有的构造方法,被jvm调用的(简单的理解:new对象或者被类加载器加载的时候),在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
Java 中所有的类型,包括 int、float 等基本类型,都有与之相关的 Class 对象。如果知道对应的 Class name,可以通过 Class.forName()
来构造相应的 Class 对象,如果没有对应的 class,或者没有加载进来,那么会抛出 ClassNotFoundException 对象。
Class获取方式
- 利用对象调用getClass()方法获取该对象的Class实例;
- 使用Class类的静态方法forName(),用类的名字获取一个Class实例 ;
- 运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例;
下面可以看看代码示例:
//方式一
Person person = new Person();
Class<? extends Person> personClazz01 = person.getClass();
//方式二
try {
Class<?> personClazz02 = Class.forName("Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式三
Class<? extends Person> personClazz03 = Person.class;
友情提示:在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。
Class中重要的方法
-
public Annotation[] getAnnotations () 获取这个类中所有注解
-
getClassLoader() 获取加载这个类的类加载器
-
getDeclaredMethods() 获取这个类中的所有方法
-
getReturnType() 获取方法的返回类型
-
getParameterTypes() 获取方法的传入参数类型
-
isAnnotation() 测试这类是否是一个注解类
-
getDeclaredConstructors() 获取所有的构造方法
-
getDeclaredMethod(String name, Class… parameterTypes) 获取指定的构造方法(参数:参数类型.class)
-
getSuperclass() 获取这个类的父类
-
getInterfaces() 获取这个类实现的所有接口
-
getFields() 获取这个类中所有被public修饰的成员变量
-
getField(String name) 获取指定名字的被public修饰的成员变量
-
newInstance() 返回此Class所表示的类,通过调用默认的(即无参数)构造函数创建的一个新实例
反射使用案例
Person类
public class Person {
private