Java核心知识——反射机制

1、理论

概念:动态获取或者动态调用对象的方法(对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性) 的功能我们称之为java语言的反射机制
程序的动态特性:大多数情况下,程序的功能是在编译的时候确定下来的,称之为静态特性;而如果程序的功能是在运行时才确定的称为动态特性。

程序动态:一般而言的动态定义是程序运行时,允许改变程序结构或变量类型,将类中的所有成员分别抽象为独立的对象,反射发生在类的加载过程

静态加载

静态加载:编译期间加载相关的类,如果没有该类就会报错,也就是我们在编写程序时是否有申明该类,所以这种方式对类与类之间的依赖关系太强

动态加载

动态加载:程序运行时按需加载要使用的类,也就是使用了懒加载机制,只有需要的时候才加载要使用的类进入内存,降低了类与类之间的依赖关系

2、Class对象

此Class非class,Class是一个类,而class是一个关键字。

获取Class对象的方式

1、类对象.getClass();------使用时期---->类运行阶段
	特点:JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象
	
2、类名.Class;-----------使用时期------>Class对象时期(内存时期)
	特点:装入类,并做类的静态初始化,返回Class的对象
	
3Class.forName("类的权限定名");-----使用时期--->字节码文件时期
	特点:对类进行静态初始化、非静态初始化;返回引用运行时真正所指的对象所属的类的Class的对象(因为:子对象的引用可能会赋给父对象的引用变量中)

3、反射机制图解

在这里插入图片描述

4、反射中的基本类

在这里插入图片描述
反射中主要用到的是前四个,最后一个是父类,所有类都是由此类扩展而来

1、Constructor类

该类用于获取指定类的构造方法

一、得到构造方法

//得到指定类的所有public修饰的构造方法
public Constructor[] getConstructors();
//得到指定类中所有的构造方法(包括 private)
public Constructor getDeclaredConstructor();
//得到指定的、被public修饰的构造方法
public Constructor getConstructor(Class ...paramType);
//得到指定的构造方法(包括private)
public Constructor getDeclaredConstructorr(Class ...paramType);

二、常用方法

getParamterTypes() //得到形参类型
newInstance(Object ...init) //实例化该对象,形参为值 : 对象.Class.getDeclaredConstructor(String.class,int.class).newInstance("向明",23);
setAccessible(boolean flag) //当得到的构造器是provate时就需要打开构造器的访问状态

2、Field类

该类用于得到指定类的字段

一、得到字段

public Field[] getFields()	
 //得到所有public修饰的字段
public Field getField(String fieldName)	
 //得到指定的、被public修饰的字段
public Field[] getDeclaredFields() 		
//得到所有的字段
public Filed getDeclaredFields(String fieldName) 	
//得到指定的字段

二、常用方法

getName()	 //得到字段名
getType() 	//得到字段类型
get(Object obj) 	//获取指定成员的值
set(Object obj , Object value) 	//将对象中指定的字段值设置成value
setAccessible(boolean flag) 	//设置私有属性的访问状态

3、Method类

该类用于得到指定类的方法

一、得到方法

public Method[] getMethods() 	
//得到所有public修饰的方法
public Method[] getDeclaredMehtods() 	
//得到所有的方法
public Method getMethod(String methodName,Class ...para) 	
//得到指定的、被public修饰的方法,methodName为方法名,para为方法中的参数,需要以Class对象的形式传入		
public Methodd getDeclaredMethod(String methodName,Class ...para) 	
//得到指定的方法,methodName为方法名,para为方法中的参数,需要以Class对象的形式传入	

二、常用方法

getName()	 //得到方法名称
getParameterTypes()	 //得到参数类型
getExceptioTypes()	 //得到抛出异常的类型
invoke(Object obj,Object ...param) 	//指定获取到了方法,obj为该方法所属的对象,param为传入的形参值

5、反射的使用

一、在后端的使用

public class BeanUtil {
	
    public static Object toVO(Class classType, Object pojo) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class cl = pojo.getClass();//得到形参对象的Class对象
        Field[] fArr = cl.getDeclaredFields();//通过形参的Class对象得到该类里的所有字段
        Method[] methods = classType.getMethods();//得到第一个形参Class对象中的所有方法
        Object object = classType.getConstructor().newInstance();//通过默认的构造器创建一个对象
        //遍历字段
        for (Field field : fArr) {
            field.setAccessible(true);//将private修饰的字段设置成允许访问
            String fieldName = field.getName();//得到字段的名称
            String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            //遍历所有得到的方法
            for (Method method : methods) {
                if (methodName.equals(method.getName())) {
                    method.invoke(object,field.get(pojo));
                }
            }
        }
        return object;
    }
}

二、在前端的使用

//前端jsp中的一个小代码块
<c:if test="${not empty loginUser}">
        <a href="address?method=show" id="a_top">${loginUser.username}</a>
        <li>|</li>
        <a href="user?method=logOut" id="a_top">注销</a>
        <li>|</li>
      	<a href="order?method=show" id="a_top">我的订单</a>
        <li>|</li>
        <a href="userservlet?method=getAddress" id="a_top">地址管理</a>
 </c:if>
//后台处理代码
 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //1.获取请求参数(标识符)
        String methodStr = req.getParameter(Constants.TAG);//得到传入的参数

        //2.如果method没有获取到值!我们就跳转到首页!(标识符异常处理)
        if (methodStr == null && methodStr.equals("")) {//判断参数是非合法
            methodStr = Constants.INDEX;
        }

        //3.反射调用对应的业务逻辑方法
        Class clazz = this.getClass();//得到本类的Class对象
        try {
        	//通过Class对象得到指定方法对象
            Method method = clazz.getMethod(methodStr, HttpServletRequest.class, HttpServletResponse.class);
           //执行通过反射得到的方法
            Object result = method.invoke(this,req,resp);
           
           //其中不重要的代码已省略。。。
        } catch (Exception e) {
            e.printStackTrace();
            //controller 和 service dao 有异常都会到此处!
            req.getSession().setAttribute("msg", "程序异常!请稍后再试!");
            resp.sendRedirect("/message.jsp");
        }

总结

使用反射的优缺点:
优点:可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等
缺点:反射使用不当会造成很高的资源消耗!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值