`

JAVA获取方法参数名的分析(一)

    博客分类:
  • Java
阅读更多

2010-5-12   魏超

 

 

关于题目

首先解释一下题目. 我们知道, Java通过反射,可以从一个类得知它有哪些方法,有哪些变量,也可以知道每个方法中有哪几个什么类型的传入参数。但有一个东西反射取不到,那就是我们对方法传入参数的命名

 

取得传入参数的名字有什么意义?

对这个问题的探究,源于在写一个测试类时候的需求。假设我们有一个类需要测试,这个类中有数十个方法。为每个方法编写测试类,将耗费大量的时间和精力。因此我有一种想法,就是通过java的反射,获得这个类所有的方法,再通过传入参数的名字和参数类型,来生成一些符合要求的数据进行传入。(能这样生成数据的前提是:这个类的编码需要遵循严格的规范,对参数的命名有统一的标准,同时,这个类应该和某种业务紧密相关,这样,才能通过业务和参数名字,判断应生成什么合适的数据)。如果能做到上面说的,那么对具有数十或数百个方法的类,要测试的话只需要传入这个类就可以了。

 

存在的问题

根据上面的设想,问题就出现了。获得类的方法,获得类的参数类型,反射都可以做到。但参数名称呢?上网求证,多数人给了直接否定的答案。因为API中根本没有提供相关的方法。但有一些人的观点启发了我。他们提到,IDE(如eclipse,myeclipse)中在编码过程中,调用一个类的方法,在代码提示的时候,ide是可以显示出方法中的参数名字的,如下图:


IDE是怎样做到的呢,如果IDE可以做到,我们是否可以尝试去分析它们的做法,来获得参数名称。

 

 

可能的做法

网上找到了一个很直观的方法——通过直接读取.java文件,把类作为一个普通文本,用正则表达式匹配方法,来直接获取参数的名字。

/**   
 *   @author   zhangc   
 *   
 *一个测试程序,用来扫描文件(java文件),找出所有方法的参数列表   
 */
import java.io.*;
import java.util.regex.*;

public class ScanSource {
	static void findArgsList(Object targetSrc) {
		/*
		 * 正则匹配串基本上是这样子分组情况(A(B(c(d))))
		 * 串是:(\\w+\\s+\\w+\\s*\\(((\\s*\\w+\\s*(\\[
		 * \\])*\\s*\\s+(\\[\\])*\\s*\\w+\\s*(\\[\\])*,?)+)\\)\\s*\\{) 比如public
		 * static void findArgsList(Object targetSrc,int []a){
		 * A是匹配整个方法定义行:这里是:static void findArgsList(Object targetSrc,int []a){
		 * B是匹配匹配参数列表:这里是Object targetSrc,int []a
		 * C是匹配一个参数,包括类型和类型名称和逗号:这里是Object targetSrc, D是匹配数组标识符:这里是[]
		 * 这个串有点bt,水平有限,只能这样
		 */
		Pattern p = Pattern
				.compile("(\\w+\\s+\\w+\\s*\\(((\\s*\\w+\\s*(\\[\\])*\\s*\\s+(\\[\\])*\\s*\\w+\\s*(\\[\\])*,?)+)\\)\\s*\\{)");
		Matcher m = p.matcher((CharSequence) targetSrc);

		// locate the all methord defination
		while (m.find()) {
			String methodName = m.group(0);
			String methodArgName = m.group(1);
			String strArgs = m.group(2);
			String fourArgs = m.group(3);
			System.out.println(methodName + "\n" + methodArgName + "\n" + strArgs + "\n" + fourArgs + "\n");
		}

	}

	public static String LoadTargetFile(String targetFileName) {
		String result = null;
		try {
			FileInputStream fis = new FileInputStream(targetFileName);

			// 临时分配10000size给byte数组。
			byte[] bufReceived = new byte[10000];

			int counts = fis.read(bufReceived);
			byte[] bufActual = new byte[counts];
			System.arraycopy(bufReceived, 0, bufActual, 0, counts);
			result = new String(bufActual);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	public static void main(String[] args) {
		String target = LoadTargetFile("src/com/spring/aop/TestAspect.java");
		System.out.println(target);
		findArgsList(target);
	}
}
 

 

 

 这个通过正则表达式的类,在我写的一个简单的测试类中,是可以取得参数的值的,但当把它用在我们那个有几十个方法的类的时候,表达式的匹配就失效了,没有得到任何的结果(具体原因可能是正则表达式的错误,没能匹配到一些方法)。同时,这种方法需要有.java这个源文件,而在IDE中引入的常常是.class组成的Jar包。为了进一步了解IDE对方法传入参数名的处理,下面我做了一个测试。

 

 

测试IDE对方法传入参数的处理

建立一个工程。在工程中新建如下的一个类:

 

 

package testplugin;

public class TestJar {
	public void testJar(String jarName, String yourName){
		System.out.println("jarName:" + jarName + "|| yourName:" + yourName);
	}
}
 

接着我们用2种方式对这个类打jar包:

 

1. 用javac编译类文件然后打到jar包中,命名为testPlugin_javac.jar.

2. 用MyEclipse直接对工程进行导出,导出为testPlugin_myeclipse.jar.

 

(打开2个jar中的TestJar.class文件,会发现2个class文件有差异)。

 

再建立一个工程,先后将2个jar包引入做实验,可以看到:

 

1. 引入testPlugin_javac.jar, 调用testJar方法,如下图



 可以看到,2个传入参数失去了原有的名称。

 

2. 移除上面的包,引入testPlugin_myEclipse.jar, 调用testJar方法,如下图



 可以看到,参数名称被识别出来了。

 

关键在于,2个jar包中的class文件不同。我们打开2个class文件(我们只是直观的看一下class文件中的变量,所以没有用专用的工具查看):

javac生成的.class:

 

 

myelipse直接打出来的.class(实际上就是调用了debug模式编译出来的.class):

 

2个class文件里下面的部分都有SourceFile块。应该是用来表示这个class文件是从哪个java文件编译来的。我们重点看上面的部分。

 

可以看到,用普通的javac编译出来的类,方法的传入参数名会被编译器修改,于是上面第一个图里SourceFile以上的部分就找不到jarName和yourName 2个名字。而只有通过-debug模式编译出来的类,它的参数名才能被保存下来。而也就是在.class文件中有保留下来参数名的jar包,在IDE中代码提示才能正确显示出参数名字。

 

那么说明IDE是否能识别类中的方法名取决于编译过后产生的不同的class文件。那么下一节我们会使用工具来解析这2个class文件来看其中到底有什么不同。

  • 大小: 30 KB
  • 大小: 28.9 KB
  • 大小: 29 KB
  • 大小: 61.7 KB
  • 大小: 109.4 KB
分享到:
评论

相关推荐

    Java实现微信公众号获取临时二维码功能示例

    主要介绍了Java实现微信公众号获取临时二维码功能,结合实例形式分析了java调用微信公众号接口实现临时二维码生成功能相关操作技巧,需要的朋友可以参考下

    java源码包---java 源码 大量 实例

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    JAVA上百实例源码以及开源项目

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    10.2.3 记得给类一个无参数的构造方法 255 10.2.4 调用父类中的构造方法 256 10.2.5 对象也会“变脸” 258 10.2.6 遵守语法,正确“变脸” 262 10.3 覆盖——与继承如影随形 264 10.3.1 当方法不再通用 264 ...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    10.2.3 记得给类一个无参数的构造方法 255 10.2.4 调用父类中的构造方法 256 10.2.5 对象也会“变脸” 258 10.2.6 遵守语法,正确“变脸” 262 10.3 覆盖——与继承如影随形 264 10.3.1 当方法不再通用 264 ...

    java开源包8

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    Java 模拟cookie登陆简单操作示例

    主要介绍了Java 模拟cookie登陆简单操作,结合实例形式分析了Java 模拟cookie登陆的相关原理与基本实现技巧,需要的朋友可以参考下

    JAVA上百实例源码以及开源项目源代码

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    125集专攻JAVA基础 JAVA零基础入门学习视频教程 动力节点JAVA视频教程.txt

    北京动力节点-Java编程零基础教程-115-Java基本语法-方法详解-方法的参数与返回值的应用场景.avi 北京动力节点-Java编程零基础教程-116-Java基本语法-方法详解-变量的作用域.avi 北京动力节点-Java编程零基础教程...

    java源码包4

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java源码包3

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    php获取不到自定义header参数原因详解

    详细分析php获取不到自定义header参数的原因,明确设置自定义header参数注意事项以及php获取自定义参数方法

    java 面试题 总结

    redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。 20、EJB与JAVA BEAN的区别? Java Bean 是可复用...

    java开源包11

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包6

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包9

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java源码包2

     Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。...

    java开源包4

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包101

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包5

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

Global site tag (gtag.js) - Google Analytics