java基础——反射

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");

注意点

  • .class方式不会引起类的初始化,而Class.forName会引起对应类进行初始化。
  • 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。
  • 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

1.2 Class提供常用方法

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

1.3 Class使用技巧

  • forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象,例如:Object obj = Class.forName("xxxx").newInstance();
  • 虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象,例如:if(e.getClass() == Employee.class)

2. reflect包

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

2.1 Field类

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

  • getFields():获得类的public类型的属性
  • getDeclaredFields():获得类的所有属性
  • getField(String name):获取指定名称public类型属性
  • getDeclaredFields(String name):获取指定名称属性

通过上述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类似如下:

  • getMethods():获得类的public类型的方法
  • getDeclaredMethods():获得类的所有方法
  • getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型,同时该方法为public的
  • getDeclaredMethod(String name, Class<?>... parameterTypes):同上只是范围扩大到所有方法

同样获取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的方法如下:

  • getConstructors():获得类的public类型的构造方法
  • getDeclaredConstructors():获取所有构造方法
  • getConstructor(Class<?>... parameterTypes):获得类的特定public构造方法,parameterTypes 参数指定构造方法的参数类型。
  • getDeclaredConstructor(Class<?>... parameterTypes):同上范围扩大到所有构造方法
    同样获取Constructor对象以后,我们可以实现以下常见功能:
  1. Class<?>[] getParameterTypes():构造方法参数列表
  2. T newInstance(Object ... initargs):实例化对应类

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

Constructor实例化对象

2.4 反射与泛型

常见两种泛型使用场景:

  • 声明一个需要被参数化(parameterizable)的类/接口,例如:class MyClass<T>
  • 使用一个参数化类,例如:List<String> arrays;
2.4.1Type接口

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

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

  • ParameterizedType: 表示一种参数化的类型,比如Collection<String>
  • GenericArrayType: 表示一种元素类型参数化类型或者类型变量数组类型
  • TypeVariable: 是各种类型变量公共父接口
  • WildcardType: 代表一种通配符类型表达式

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

  • 含义:表示参数化类型比如:Map<String, Date>这种参数化类型
  • Type[] getActualTypeArguments():获取参数化类型<>中的实际类型(注意对于多次嵌套,该方法只返回脱去最外层的<>以后剩下内容返回)
  • 关于返回值是数组因为存在Map<String, Date>返回不止一种类型
  • 为什么返回父接口,因为返回值多态性,对于ArrayList<ArrayList<Integer>>返回的是ArrayList<Integer>ParameterizedType类型的,而对于ArrayList<E>返回的是E是TypeVariable类型,而对于 对于ArrayList<E[]>返回的是E[]则对应的是GenericArrayType类型。
  • Type getRawType():获取承载该泛型信息的对象,该类型表示<>前面的类型比如Map<String,String>,则返回Map
2.4.2参数化类型反射获取

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

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

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

getGenericReturnType
getReturnType

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

  • Field类中属性类型 Class<?> getType()和Type getGenericType()
  • Method类中方法返回值类型Class<?> getReturnType() 和Type getGenericReturnType()
  • Method类中方法参数类型Class<?>[] getParameterTypes()和Type[] getGenericParameterTypes()
  • Constructor类中方法参数和Method中方法参数完全一致

最后,如果需要解析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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容