之前我们已经介绍了Java中框架常用的技术---反射。可以这么说反射方便了我们的开发。今天我们来说说他的短板,或者说我们今天在反射的基础上在进行方便化。

反射操作方法

在上一章节中我们学会了通过反射去调用方法。

public class App {
public void test(String str, Integer integer) {
System.out.println(str);
System.out.println(integer);
}
}

这个时候如果我想获取test方法对象的话应该这么做

Method testMethod = App.class.getMethod("test", String.class, Integer.class);

这里就不在赘述如何通过Method对象调用方法了。文章末尾会给出上一章节的地址。今天我们要研究的是Method如何获取方法参数这一块。看似简单却又是那么的传奇。我们看看下面一段代码执行的效果

public static void main(String[] args) throws ParseException, NoSuchMethodException {
Method[] methods = App.class.getMethods();
Method testMethod = App.class.getMethod("test", String.class, Integer.class);
Class<?>[] parameterTypes = testMethod.getParameterTypes();
Parameter[] parameters = testMethod.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter.getName());
}
}

那么输出的两个参数名称是什么呢?一开始笔者这里想当然的认为是 str , name 。 相信此时的你应该和我一样认为是str , name 。

对的,你没看错返回的居然是无意义的名称 , arg0 , arg1.这就奇怪了。至于为什么呢?我现在还不想告诉你。下面会慢慢告诉你。

Spring的方法的优点

做过Javaweb开发的肯定都用过spring,springmvc , 在写controller层的时候我们都会在方法里直接写key值的名称,然后在请求地址中给相应的key赋值。

@RequestMapping(value = "/deptId", method = RequestMethod.GET)
public PagedResult<SysDept> selectSysDeptsByPK(Integer pageNumber, Integer pageSize) {
return sysDeptService.selectSysDeptsByPK(deptId, pageNumber, pageSize);
}

上述的controller我们在前端发送请求后会这样发送

http://{ip}:{port}/{projectName}/deptId?pageNumber=1&pageSize=5

这里我问一下你们有没有想过为什么springmvc它能够通过你传递的参数一一进行对应呢?我们上面已经尝试过通过反射是无法获取方法参数名称的。而springmvc无非就是反射操作方法的。这里是不是很神奇,不得不佩服springmvc的强大。强大到让人害怕。

反射如何实现Spring的方法

上面两个案例揭露了反射的缺点以及springmvc的强大。这里需要借助springmvc提供的一个工具ParameterNameDiscoverer 。 这个类顾名思义就是发现参数名称。在使用这个类之前我们先来了解下为什么反射获取不到方法名称。

这里需要简单说说Java执行过程,Java之所以可以跨容器是因为Java针对各个系统提供了不同jvm,所以我们开发前都需要安装不同版本的jdk,jdk里面提供了jvm,java 代码运行期间是通过jvm去操作class文件的。但是我们平时都是开发java文件的。所以在jvm执行之前会有一个编译期间。javac就是用来变异java文件为class文件的。

package com.zxhtom.test;

/**
* Hello world!
*/
public class App {
public void test(String str, Integer integer) { }
}

针对上述代码我们通过javac进行编译下试试看看效果。

javac App.java

编译完成之后会出现一个同名的class文件

然后我们在通过命令查看下这个class文件

javap -verbose App.class



通过查看App.java对应的字节码发现在javac编译的时候对于方法的名称根本不会去记录的。想想也对我执行方法的时候只需要按顺序将参数放进去就行了。根本不需要关心参数名称是什么。那么问题显而易见了jvm不需要参数名所以编译时过率了。但是我们反射想通过参数名称一一对应这样效率更快。那么是springmvc是如何解决的呢。

private static final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public static void main(String[] args) throws ParseException, NoSuchMethodException {
java.lang.reflect.Method testMethod = App.class.getMethod("test", String.class, Integer.class);
String[] parameterNames = parameterNameDiscoverer.getParameterNames(testMethod);
for (String parameterName : parameterNames) {
System.out.println(parameterName);
}
}



对,就是ParameterNameDiscoverer这个方法帮助了我们。这里简单说说ParameterNameDiscoverer作用。springmvc中会有一个默认的ParameterNameDiscoverer解释器DefaultParameterNameDiscoverer该类继承PrioritizedParameterNameDiscoverer。PrioritizedParameterNameDiscoverer这个类就是getParameterNames去获取方法名的。在springmvc中通过addDiscoverer方法有三个类注册到PrioritizedParameterNameDiscoverer

  • KotlinReflectionParameterNameDiscoverer : Spring5.0提供 ,但是也得jdk8及以上版本使用
  • StandardReflectionParameterNameDiscoverer : Spring4.0提供 ,但是也得jdk8及以上版本使用
  • LocalVariableTableParameterNameDiscoverer :Spring2.0就有了,对JDK版本没啥要求,完全Spring自己实现的获取字段名称,逻辑复杂些,效率稍微低一点

总结一下就是在springmvc4.0之前springmvc都是通过自己实现的一套代码去获取字节码然后分析的。这里能力有限就不分析了。

在4.0以后因为Java8的推出弥补了这个bug.springmvc也就都采用jdk提供的功能获取参数名了。下面我们来看看jdk8是如何解决这个问题的。

Java字节码

在上一节我们通过javac , javap命令进行了Java的编译了查看。我们发现class字节码中记录的信息有【常量区,类,方法】其中对于代码的记录有位置,堆,栈,行号等等。这也是我们jvm调优的依据。但是这仅仅是我们使用简单的javac的编译。

javac -g : 编译更加全面点



经过对比发现javac 和javac -g 的区别好像是javac -g 编译信息多出LocalVariableTable信息。

名称 解释
LineNumberTable 属性表存放方法的行号信息
LocalVariableTable 属性表中存放方法的局部变量信息

上图中通过javac -g 编译的信息中LocalVarableTable有三条数据,是因为在编译期间每个非静态方法第一个参数都是this.去除第一条剩下的其实就是我们需要的参数信息。但是我们这个时候去执行一下看看效果。

高级反射注意点

所谓的高级反射其实就是对jdk版本的要求,只要是jdk8的版本,就可以用jdk提供的parameter方法获取参数名了。在编译的时候需要加上 -parameters

javac的彩蛋

续点

每日一笑

今天公司放假,和老婆商量好一起去她家,出发前夕,老婆说:给我家里人的礼物买好了么?然后我去卧室全搬出来了;给她说:这是你舅的,这是你叔的,这是你爷爷的,这是你奶奶的,这是你爸的,这是你妈的,这是…………然后我俩就打起来了!

上期答案

无

加入战队

# 加入战队

微信公众号

你以为反射真的无所不能?至少JDK8以后很强大的更多相关文章

  1. 值得推荐的C/C++框架和库 (真的很强大) c

    http://m.blog.csdn.net/mfcing/article/details/49001887 值得推荐的C/C++框架和库 (真的很强大) 发表于2015/10/9 21:13:14 ...

  2. ReSharper的功能真的很强大主要是针对代码规范和优化,园子里介绍的也不少,如果你没有安装,那我只能表示你们会相见恨晚

    二.ReSHarper 代码规范.单元测试.... ReSharper的功能真的很强大,主要是针对代码规范和优化,园子里介绍的也不少,如果你没有安装,那我只能表示你们会相见恨晚! 1.像命名不规范,f ...

  3. 【转】 值得推荐的C/C++框架和库 (真的很强大)

    [转] 值得推荐的C/C++框架和库 (真的很强大) 值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个 ...

  4. 真的可以啊,用C语言实现面向对象编程O O P!C语言真的无所不能~

    解释区分一下C语言和OOP 我们经常说C语言是面向过程的,而C++是面向对象的,然而何为面向对象,什么又是面向过程呢?不管怎么样,我们最原始的目标只有一个就是实现我们所需要的功能,从这一点说它们是殊途 ...

  5. 转:值得推荐的C/C++框架和库(真的很强大)

    目录(?)[+] 值得学习的C语言开源项目 - 1 Webbench - 2 Tinyhttpd - 3 cJSON - 4 CMockery - 5 Libev - 6 Memcached - 7 ...

  6. 值得推荐的C/C++框架和库 (真的很强大)

    值得学习的C语言开源项目 - 1. Webbench Webbench是一个在Linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...

  7. Python小白绘图 哆唻A梦 turtle真的很强大!

    # -*- coding: utf-8 -*- """ Created on Sat Nov 10 22:02:32 2018 @author: 10029 " ...

  8. 值得推荐的C/C++框架和库 (真的很强大)〔转〕

    http://m.blog.csdn.net/article/details?id=42541419

  9. C/C++框架和库 (真的很强大) 转

    http://blog.csdn.net/xiaoxiaoyeyaya/article/details/42541419     值得学习的C语言开源项目 - 1. Webbench Webbench ...

随机推荐

  1. npm钉钉脚手架,支持考勤信息获取

    钉钉官方并未提供nodejs包,第一次调用接口的时候非常费事,而且尝试去寻找相关的钉钉考勤数据模块的时候只找到了一些消息啊,只能办公啊,免登啊之类的模块,有关考勤数据的似乎没有 关于dd的npm包中一 ...

  2. 40 篇原创干货,带你进入 Spring Boot 殿堂!

    两个月前,松哥总结过一次已经完成的 Spring Boot 教程,当时感受到了小伙伴们巨大的热情. 两个月过去了,松哥的 Spring Boot 教程又更新了不少,为了方便小伙伴们查找,这里再给大家做 ...

  3. 【模板】树链剖分(Luogu P3384)

    题目描述 众所周知 树链剖分是个好东西QWQ 也是一个代码量破百的算法 基本定义 树路径信息维护算法. ž将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN). 其实本质是一些数据结 ...

  4. 关于事务,事务的特性,spring事务的传播特性

    1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功,要么失败). 2.事务特性: 事务特性分为四个:原子性(At ...

  5. Vue入门到TodoList练手

    学习资料 慕课网 - vue2.5入门 基础语法 示例代码1 <div id="root"> <h1>hello {{msg}}</h1> &l ...

  6. 通过视图实现自定义查询<持续完善中。。。>

    目前实现: ----普通查询路径 /viewShow/viewShow/list.htm ----Echarts查询路劲 /viewShow/viewShow/echarts.htm 1.自定义查询条 ...

  7. 设计模式(C#)——11代理模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321 前言        在软件开发过程中,当无法直接访问某个对象或访问某个对象存在困难时,我们希望可以通过一个中介来间接访问,这就是 ...

  8. Unity官方案例精讲_2015_优化

    1.将公共变量从Inspector视图中隐藏:    [HideInInspector] [HideInInspector] public GameObject player; 2.限定Inspect ...

  9. HDU 1847

    题意略. 思路:又忘了dp,搜索这种暴力方法了.... #include<bits/stdc++.h> using namespace std; ; bool sg[maxn]; int ...

  10. HDU 6040

    题意略. 思路:题目就是在询问你m次,第k小是哪个数.首先我们可以想到直接排序后,即可O(1)来查找询问.但是题目中n的范围给的是1e7, 无法承受nlogn的复杂度.从而想到另外一种求静态第k小的方 ...