简要介绍Android反射原理
在这篇文章中简要对反射原理进行讲解,希望能够通过这篇文章对反射原理有一个归纳性的了解,并掌握一定的使用方式。
首先,我们来了解下,什么是反射?
实际上Android的反射原理也是基于Java本身的一个反射机制。主要是指可以通过代码程序进行访问、检测和修改它本身状态或行为的一种能力。
那么如何获取反射的类或者方法呢,下面就简要的讲诉下获取反射的主要方法。
通过反射加载类
如下我们可以通过JVM对我们想要的类进行查找,然后将获得的Class对象进行加载,这样我们就能获取到一个简要的Class类的对象了,并通过调用newInstance()方法让加载完的类在内存中创建对应的实例,并把实例赋值给我们要进行查找的类。
通过Class的forName方法的进行反射获取的源码例子如下:
Class<?> cls=Class.forName("com.test.PackageNameTest"); //forName(包名.类名)
PackageNameTest test=(PackageNameTest)cls.newInstance();
在这里需要先引入一个概念,就是类加载概念,当使用一个类的时候(比如new一个类的实例),jvm会检查此类是否被加载到内存,如果没有,则会执行加载操作,加载操作的内容是,读取类对应的class文件数据,解析此数据,构造一个此类对应的Class类的实例,此Class类的实例描述了类的结构,并且提供了调用此类成员的接口。此时jvm就可以使用该类了,比如实例化此类,或者调用此类的静态方法。
而我们这里使用的forName方法其实就是JVM类加载中的手动加载方法,目的都是为了获取这个类的实例。其中,在金使用这个类前都会默认进行类初始化,类初始化操作就是执行一遍类的静态语句,包括静态变量的声明还有静态代码块。稍微注意的是,这里并不包括静态方法。
那么除了通过forname的方式获取到类还可以通过getClass和ClassLoad进行装载。
ClassLoad方式装载
PackageNameTest t = new PackageNameTest();
Class<?> cls=t.getClass();//getClass 方式,返回类对象运行时真正所指的对象,所属类型的Class对象
PackageNameTest tt=(PackageNameTest)cls.newInstance();
getClass方式装载
Class<?> cls=PackageNameTest.Class();//.class 方式,ClassLoader 装载入内存,不对类进行类的初始化操作
PackageNameTest t=(PackageNameTest)cls.newInstance();
通过反射加载函数
其实和前面加载类的方式相似,可以通过get的方式进行对应类型的获取。首先先获取这个类,我这里依照方法,和变量名举个例子:
如下为反射构造函数:
Class c1 = PackageNameTest.class;
// getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数
try {
Constructor constructor1 = c1.getConstructor(String.class);
} catch (NoSuchMethodException e) { //没此函数的异常捕获
e.printStackTrace();
}
如下为反射方法:
Class c2 = PackageNameTest.class;
// 根据方法名和参数,返回一个具体的具有public属性的方法
try {
Method method1 = c2.getMethod("testPublicVoidMethod", null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
如下为反射变量:
Class c3 = PackageNameTest.class;
// getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
try {
Field field1 = c3.getField("mPublicStr");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
那么通过这些方式就可以在Android中简要通过反射来获取自己想要的类,方法,变量等等。可能这里不禁会产生一个问题,为什么要通过反射来获取,直接new一个,它不香吗?
我们来看看下面这这张图:
上面这张是Java的内存模型图,在程序运行时,Jvm会将方法,类进行加载创建放入内存区。当然,在加载前会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是之前说的new一个对象。但这里的对象创建是在程序初始化的时候进行的,我们不可能在运行的时候还可以进行这样的操作。
为了更好的说明,我这边举个常用的例子,数据库在进行驱动加载的时候,可能会发现加载的这个驱动类不是我目前所需要的,那么如何将它变成我需要的,这时候反射就派上用场了。又或者说,很多时候的源代码我们是获取不到的,那么利用反射创建一个类,而反射需要的参数是一个字符串,我们将字符串存入配置文件中,这样,我们修改配置文件即可动态产生不一样的代码了,为了适应各种需求,这种情况在很多框架中常常出现。
反射常用方法
如下为在反射中会常常用到的一些方法,可以通过这些方法更好的获取我们想要的一些内容。
方法关键字 | 含义 |
---|---|
getDeclareMethods() | 获取所有的方法 |
getReturnType() | 获取方法的返回值类型 |
getParameterTypes() | 获取方法的传入参数类型 |
getDeclareMethod(“方法名,参数类型.class,…”) | 获得特定的方法 |
构造方法关键字 | 含义 |
---|---|
getDeclaredConstructors() | 获取所有的构造方法 |
getDeclaredConstructors(参数类型.class,…) | 获取特定的构造方法 |
成员变量 | 含义 |
---|---|
getDeclaredFields | 获取所有成员变量 |
getDeclaredField(参数类型.class,…) | 获取特定的成员变量 |
父类和父接口 | 含义 |
---|---|
getSuperclass() | 获取某类的父类 |
getInterfaces() | 获取某类实现的接口 |
到此就是简要介绍在Android中的反射简单使用和原理介绍了,欢迎讨论交流。
参考文章
Android 反射机制的理解
https://www.jianshu.com/p/7fdb8c828602
Android 反射机制
https://www.jianshu.com/p/88ecd6e1a28b