关于JAVA语言反射机制的浅析
小标 2018-09-11 来源 : 阅读 1133 评论 0

摘要:本文主要向大家介绍了关于JAVA语言反射机制的浅析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了关于JAVA语言反射机制的浅析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

什么是反射

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

初探

对反射的最初接触是学习jdbc时,加载数据库驱动时会这样写:Class.forName("com.mysql.jdbc.Driver"),当时似懂非懂的也不知道是什么意思,随着自己的不断学习,越来越感觉反射的神奇,让我们一起来揭开它的神秘面纱吧。

学习一个知识,自然是最先从api开始,反射涉及的类,除了Class类之外,基本上都在java.lang.reflect包里面,常用的类有Constructor,Field,Method类等,AccessibleObject类是前面三个类的基类,主要包含设置安全性检查等方法,下面,我们看一下reflect包的结构


可以看出,涉及的类并不多,让我一起来看一下其中比较常用的类的用法吧

初始化

测试用例采用junit+log4j,新建一个test类,一个javabean

其中name属性get,set方法用private修饰

User类

package com.test;public class User {  private String name = "init";  private int age;  public User() {}  public User(String name, int age) {    super();    this.name = name;    this.age = age;
 }  private String getName() {    return name;
 }  private void setName(String name) {    this.name = name;
 }  public int getAge() {    return age;
 }  public void setAge(int age) {    this.age = age;
 }  @Override
 public String toString() {    return "User [name=" + name + ", age=" + age + "]";
 }
}

Test类

public class ReflectTest {  private static Logger logger = Logger.getLogger(ReflectTest.class);  private static Class<User> userClass = User.class;
}

在类加载的时候,jvm会创建一个class对象

class对象是可以说是反射中最常用的,获取class对象的方式的主要有三种

根据类名:类名.class

根据对象:对象.getClass()

根据全限定类名:Class.forName(全限定类名)

 @Test
 public void classTest() throws Exception {    // 获取Class对象的三种方式
   logger.info("根据类名:  \t" + User.class);
   logger.info("根据对象:  \t" + new User().getClass());
   logger.info("根据全限定类名:\t" + Class.forName("com.test.User"));    // 常用的方法
   logger.info("获取全限定类名:\t" + userClass.getName());
   logger.info("获取类名:\t" + userClass.getSimpleName());
   logger.info("实例化:\t" + userClass.newInstance());
 }

console

根据类名:   class com.test.User根据对象:   class com.test.User根据全限定类名:    class com.test.User获取全限定类名:    com.test.User获取类名:   com.test.User实例化:    User [name=init, age=0]

构造函数

构造函数是java创建对象的必经之路,所以通过反射拿到一个类的构造函数后,再去创建这个类的对象自然是易如反掌,常用的方法如下:

 @Test
 public void constructorTest() throws Exception {    // 获取全部的构造函数
   Constructor<?>[] constructors = userClass.getConstructors();    // 取消安全性检查,设置后才可以使用private修饰的构造函数,也可以单独对某个构造函数进行设置
   // Constructor.setAccessible(constructors, true);
   for (int i = 0; i < constructors.length; i++) {
     Class<?> parameterTypesClass[] = constructors[i].getParameterTypes();
     System.out.print("第" + i + "个构造函数:\t (");      for (int j = 0; j < parameterTypesClass.length; j++) {
       System.out.print(parameterTypesClass[j].getName() + (j == parameterTypesClass.length - 1 ? "" : "\t"));
     }
     logger.info(")");
   }    // 调用构造函数,实例化对象
   logger.info("实例化,调用无参构造:\t" + constructors[0].newInstance());
   logger.info("实例化,调用有参构造:\t" + constructors[1].newInstance("韦德", 35));
 }

console

第0个构造函数:     ()
第1个构造函数:     (java.lang.String  int)
实例化,调用无参构造: User [name=init, age=0]
实例化,调用有参构造: User [name=韦德, age=35]

属性

犹记得学习spring ioc之时,对未提供set方法的private属性依然可以注入感到神奇万分,现在看来,这神奇的根源自然是来自于java的反射,常用的方法如下:

 @Test
 public void fieldTest() throws Exception {
   User user = userClass.newInstance();    // 获取当前类所有属性
   Field fields[] = userClass.getDeclaredFields();    // 获取公有属性(包括父类)
   // Field fields[] = cl.getFields();
   // 取消安全性检查,设置后才可以获取或者修改private修饰的属性,也可以单独对某个属性进行设置
   Field.setAccessible(fields, true);    for (Field field : fields) {      // 获取属性名 属性值 属性类型
     logger.info("属性名:" + field.getName() + "\t属性值:" + field.get(user) + "  \t属性类型:" + field.getType());
   }
   Field fieldUserName = userClass.getDeclaredField("name");    // 取消安全性检查,设置后才可以获取或者修改private修饰的属性,也可以批量对所有属性进行设置
   fieldUserName.setAccessible(true);
   fieldUserName.set(user, "韦德");    // 可以直接对 private 的属性赋值
   logger.info("修改属性后对象:\t" + user);
 }

console

属性名:name    属性值:init    属性类型:class java.lang.String属性名:age 属性值:0   属性类型:int修改属性后对象:    User [name=韦德, age=0]

方法

大家对javabean肯定不会陌生,在用框架操作javabean时,大多都是通过反射调用get,set方法Javabean进行操作,常用的方法如下:

 @Test
 public void methodTest() throws Exception {
   User user = userClass.newInstance();    // 获取当前类的所有方法
   Method[] methods = userClass.getDeclaredMethods();    // 获取公有方法(包括父类)
   // Method[] methods = userClass.getMethods();
   // 取消安全性检查,设置后才可以调用private修饰的方法,也可以单独对某个方法进行设置
   Method.setAccessible(methods, true);    for (Method method : methods) {      // 获取方法名和返回类型 获取参数类型:getParameterTypes
     logger.info("方法名:" + method.getName() + " \t返回类型:" + method.getReturnType().getName());
   }    // 获取无参方法
   Method getMethod = userClass.getDeclaredMethod("getName");    // 取消安全性检查,设置后才可以调用private修饰的方法,也可以批量对所有方法进行设置
   getMethod.setAccessible(true);    // 调用无参方法
   logger.info("调用getName方法:" + getMethod.invoke(user));    // 获取有参方法
   Method setMethod = userClass.getDeclaredMethod("setName", String.class);    // 取消安全性检查,设置后才可以调用private修饰的方法,也可以批量对所有方法进行设置
   setMethod.setAccessible(true);    // 调用有参方法
   logger.info("调用setName方法:" + setMethod.invoke(user, "韦德"));
   logger.info("通过set方法修改属性后对象:\t" + user);
 }

console

方法名:toString    返回类型:java.lang.String
方法名:setAge  返回类型:void方法名:getAge  返回类型:int方法名:getName     返回类型:java.lang.String
方法名:setName     返回类型:void调用getName方法:init
调用setName方法:null通过set方法修改属性后对象: User [name=韦德, age=0]

完整的 源码 https://github.com/zhaoguhong/blogsrc

总结

不难看出,Java反射中的构造函数,属性,方法有着诸多相似之处,不仅仅是因为它们有着共同的父类AccessibleObject,基本上所有的api都有相似之处。学习的过程中死记api是最愚蠢的,找方法,理解反射的设计思路。去尝试感悟设计思想,才是王道。

上面只是对反射的常用方法提供了示例,最好的学习方法自然是参照api,自己去实践。纸上得来终觉浅,绝知此事要躬行。通过自己的不断练习,体会,思考,达到融会贯通的目的。

思考

java以面向对象和封装性著称,但反射在java中堪称作弊器,似乎无所不能,给人一种建了一道围墙,下面又留了一道门的感觉,是否破坏了程序的封装性?

笔者认为:循规蹈矩固然好,但过于注重规范反而影响程序的灵活性。Java反射给我们带了灵活性的同时,极大的方便了我们的编程,而且反射堪称各大框架的基础。如此看来,显然利大于弊,你怎么看?

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程