android杂记Android知识Java学习笔记

java基础——反射

2016-12-23  本文已影响321人  陈晨_Fly

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Class类和java.lang.reflect类库一起对反射机制进行了支持,该类库包含了Field、Method以及Constructor类。下面就从这两大方面对反射进行介绍:

1. Class类

类作为程序的一部分,每个类都拥有一个Class对象。每当编写并编译一个新类,就会产生一个Class对象(保存在一个同名的.class文件中)。为了生成这个类的对象,jvm使用了类加载器系统。
所有的类都是在第一次使用时,动态加载到jvm中的。类加载器首先检查这个类的Class对象是否已经加载,未加载就会查找.class文件(本地或网络获取)。

1.1 Class类获取

以下三种方式均可以获取Class类:

return reportInfo;
Integer num = new Integer(123);
Class c1 = num.getClass();
Class c2 = Integer.class;
Class c3 = Class.forName("java.lang.Integer");
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class cl4 = loader.loadClass("java.lang.Integer");

注意点

1.2 Class提供常用方法

  1. getClassLoader() :返回该类的类加载器
  2. isArray() :判断是否是数组
  3. getName():以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称
  4. newInstance():可以创建该类的示例
  5. 同时提供了获取Constructor、Method和Field的方法,后续会详细说明

1.3 Class使用技巧

2. reflect包

reflect包中有三个类,Field,Method,Constructor,分别去描述类的域,方法,构造器。
通过Class类可以分别获取上述三个类的具体实例,下面进行分别讲述:

2.1 Field类

表示类的成员变量,其中一个成员变量对应一个Field对象。Class对象获取Field方法如下:

通过上述4种方法,我们可以获取指定的Field对象。通过Field对象我们可以实现以下常见功能:

  1. String getName():获取字段名
  2. Class<?> getType() 和 Type getGenericType() :获取类型和泛型
  3. int getModifiers():获取修饰
  4. Object get(Object obj):获取指定对象该字段对应值
  5. void set(Object obj, Object value):给指定对象的该段赋值

这里演示一下如何修改private的属性值:

修改private属性值

这里需要注意的是在赋值给private属性之前需要调用field.setAccessible(true)方法关闭对private属性访问检查。

2.2 Method类

表示类的成员方法,其中一个成员方法对应一个Method对象。Class对象获取Method方法与Filed类似如下:

同样获取Method对象以后,我们可以实现以下常见功能:

  1. Class<?>[] getParameterTypes():获取该方法的所有参数类型
  2. Class<?> getReturnType():获取该方法返回值
  3. <T extends Annotation> T getAnnotation(Class<T> annotationClass):获取方法注解
  4. Object invoke(Object obj, Object... args)执行该方法

同样这里演示如何执行一个private方法:

执行private方法

同样在执行private方法之前需要执行method.setAccessible(true),关闭对private方法访问检查。

2.3 Constructor类

表示类的构造方法,其中一个构造方法对应一个Constructor对象。Class获取Constructor的方法如下:

  1. Class<?>[] getParameterTypes():构造方法参数列表
  2. T newInstance(Object ... initargs):实例化对应类

接下来示例展示如何利用Constructor对象实例化对应类

Constructor实例化对象

2.4 反射与泛型

常见两种泛型使用场景:

2.4.1Type接口

在此之前我们需要介绍一下Type接口,Java编程语言中所有类型公共父接口,这里所说的所有类型包括:
原始类型 (raw types)对应Class,参数化类型 (parameterizedtypes)对应ParameterizedType, 数组类型 (array types)对应GenericArrayType,类型变量 (type variables)对应TypeVariable,基本数据类型(primitivetypes)仍然对应Class。

Class类实现了该接口,同时该接口的直接子接口包括以下4个:

配合后面的反射内容重点介绍一下java.lang.reflect.ParameterizedType接口

2.4.2参数化类型反射获取

讲述完Type相关内容以后,我们来看下Field、Method和Constructor相关类如何获取泛型参数或泛型返回值。这里我们以Method为例说明:

方法返回值参数化类型获取

在这个示例中我们重点关注一下method.getGenericReturnType()方法,返回返回值Type,查看jdk源码:

getGenericReturnType getReturnType

观察代码可以发现在获取泛型返回是首先判断getGenericSignature()是否为空该函数是native的没找到相关资料,从名称推断是标识是否是泛型,在Field相关源码中也有出现。如果返回不问空则返回ParameterizedType类型,否则调用getReturnType返回Class<?>类型。
查看Field、Constructor相关代码可以看出相似使用方法:

最后,如果需要解析Field、Method、Constructor中泛型相关类型,使用步骤和给出示例类似:

  1. 调用相关Genric对应的方法
  2. 判断返回值instanceof ParameterizedType
  3. 步骤为true强制转换为ParameterizedType类型
  4. 后续调用getActualTypeArguments等方法获取真实参数

参考文档

http://lavasoft.blog.51cto.com/62575/15433/
http://developer.51cto.com/art/201103/250028.htm
http://blog.csdn.net/benjaminzhang666/article/details/9838937

上一篇 下一篇

猜你喜欢

热点阅读